T-SQL 枢轴,对枢轴结果进行计数
T-SQL pivot with count on pivoted results
我有以下数据,我想对它们进行透视并根据透视后的结果进行计数。
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255),
expertise INT)
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname, expertise)
SELECT 'Foster','Matt','Guitar','10'
UNION
SELECT 'Foster','Jimmy','Guitar','5'
UNION
SELECT 'Foster','Jimmy','Keyboard','8'
UNION
SELECT 'Foster','Ryan','Keyboard','9'
UNION
SELECT 'Midlothean','Kyle','Keyboard','10'
UNION
SELECT 'Midlothean','Mary','Guitar','4'
UNION
SELECT 'Midlothean','Mary','Keyboard','7'
原始数据:
我希望结果看起来像下面的数据....
我使用下面的 sql 查询获得了这些数据。这个查询的问题是我有一个动态数量的工具(为了简单起见,我在这个例子中只显示了 2 个)。我想使用 pivot,因为它会更清晰动态 sql。否则,我将不得不为每个乐器动态地将 table 加入自身。
SELECT
t.school, t.instrumentname, t.expertise,
t1.instrumentname, t1.expertise,
COUNT(DISTINCT t.studentname) [DistinctStudentCount]
FROM
@tempMusicSchoolStudent t
LEFT JOIN
@tempMusicSchoolStudent t1 ON t1.school = t.school
AND t1.studentname = t.studentname
AND t.instrumentname <> t1.instrumentname
GROUP BY
t.school, t.instrumentname, t.expertise, t1.instrumentname, t1.expertise
ORDER BY
t.school, t.instrumentname, t.expertise, t1.instrumentname, t1.expertise
如果有人对我如何以一种比动态左连接 table 更简洁的方式做到这一点有任何想法,我们将不胜感激。谢谢。
您只需要条件聚合:
SELECT t.school, t.instrumentname, t.expertise, t.instrumentname,
COUNT(DISTINCT t.studentname) as DistinctStudentCount
FROM @tempMusicSchoolStudent t
GROUP BY t.school, t.instrumentname, t.expertise, t.instrumentname;
您有包含 NULL
个值的行。完全不清楚这些是从哪里来的。您的问题集中在 "pivoting" 的某些概念上,您似乎只需要聚合。但它没有解释 NULL
行的来源。
您可以尝试使其针对多种乐器动态化。
;with cte
as
(
SELECT * from
(SELECT * FROM @tempMusicSchoolStudent t) x
PIVOT
(MAX(expertise) FOR instrumentname in ([Guitar], [Keyboard])) y
)
SELECT school, studentname,
expertise = case when Guitar is not null then 'Guitar' else NULL end,
Guitar AS instrumentname,
expertise = case when Keyboard is not null then 'Keyboard' else NULL end,
Keyboard AS instrumentname,
count(distinct studentname) AS [DistinctStudentCount]
from cte
group by school,studentname, Guitar, Keyboard
输出:
Foster Jimmy Guitar 5 Keyboard 8 1
Foster Matt Guitar 10 NULL NULL 1
Foster Ryan NULL NULL Keyboard 9 1
Midlothean Kyle NULL NULL Keyboard 10 1
Midlothean Mary Guitar 4 Keyboard 7 1
这是我一直在寻找的解决方案,我不得不使用 unpivot + pivot。
真正让我苦恼的是为要旋转的列选择多个值,而不是最大值。
所以在这种情况下,我希望在给定的 "instrument expertise" 列下有多个 "expertise" 数字。不仅仅是该仪器的最大专业知识。
理解解决方案的第一个关键是 pivot 语句对所选列进行隐式分组。因此,为了在您的透视列下实现多个值,您必须通过包含某种类型的 dense_rank/rank/row_number 来保持您分组的列的完整性。这基本上代表了您正在旋转的列的值的变化,然后被旋转包含在隐式组中,这导致在旋转列中获得多个值,而不仅仅是最大值。
所以在下面的代码中,"expertisenum" 列保持了专业知识数据的完整性。
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255),
expertise INT)
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname, expertise)
SELECT 'Foster','Matt','Guitar','10'
UNION
SELECT 'Foster','Jimmy','Guitar','5'
UNION
SELECT 'Foster','Jimmy','Keyboard','8'
UNION
SELECT 'Foster','Ryan','Keyboard','9'
UNION
SELECT 'Midlothean','Kyle','Keyboard','10'
UNION
SELECT 'Midlothean','Mary','Guitar','4'
UNION
SELECT 'Midlothean','Mary','Keyboard','7'
SELECT school, [Guitar expertise], [Keyboard expertise], COUNT(*) [Count]
FROM
(
SELECT school,[expertiseNum],
CASE WHEN [Columns]='expertise' THEN instrumentname + ' expertise'
END [Columns1], [Values] AS [Values1]
FROM
(
SELECT school, studentname, instrumentname, DENSE_RANK() OVER(PARTITION BY school,instrumentname ORDER BY expertise) AS [expertiseNum],
CONVERT(VARCHAR(255),expertise) AS [expertise]
FROM @tempMusicSchoolStudent
) x
UNPIVOT (
[Values] FOR [Columns] IN ([expertise])
) unpvt
) p
PIVOT (
MAX([Values1]) FOR [Columns1] IN ([Guitar expertise], [Keyboard expertise])
) pvt
GROUP BY school,[Guitar expertise], [Keyboard expertise]
我有以下数据,我想对它们进行透视并根据透视后的结果进行计数。
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255),
expertise INT)
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname, expertise)
SELECT 'Foster','Matt','Guitar','10'
UNION
SELECT 'Foster','Jimmy','Guitar','5'
UNION
SELECT 'Foster','Jimmy','Keyboard','8'
UNION
SELECT 'Foster','Ryan','Keyboard','9'
UNION
SELECT 'Midlothean','Kyle','Keyboard','10'
UNION
SELECT 'Midlothean','Mary','Guitar','4'
UNION
SELECT 'Midlothean','Mary','Keyboard','7'
原始数据:
我希望结果看起来像下面的数据....
我使用下面的 sql 查询获得了这些数据。这个查询的问题是我有一个动态数量的工具(为了简单起见,我在这个例子中只显示了 2 个)。我想使用 pivot,因为它会更清晰动态 sql。否则,我将不得不为每个乐器动态地将 table 加入自身。
SELECT
t.school, t.instrumentname, t.expertise,
t1.instrumentname, t1.expertise,
COUNT(DISTINCT t.studentname) [DistinctStudentCount]
FROM
@tempMusicSchoolStudent t
LEFT JOIN
@tempMusicSchoolStudent t1 ON t1.school = t.school
AND t1.studentname = t.studentname
AND t.instrumentname <> t1.instrumentname
GROUP BY
t.school, t.instrumentname, t.expertise, t1.instrumentname, t1.expertise
ORDER BY
t.school, t.instrumentname, t.expertise, t1.instrumentname, t1.expertise
如果有人对我如何以一种比动态左连接 table 更简洁的方式做到这一点有任何想法,我们将不胜感激。谢谢。
您只需要条件聚合:
SELECT t.school, t.instrumentname, t.expertise, t.instrumentname,
COUNT(DISTINCT t.studentname) as DistinctStudentCount
FROM @tempMusicSchoolStudent t
GROUP BY t.school, t.instrumentname, t.expertise, t.instrumentname;
您有包含 NULL
个值的行。完全不清楚这些是从哪里来的。您的问题集中在 "pivoting" 的某些概念上,您似乎只需要聚合。但它没有解释 NULL
行的来源。
您可以尝试使其针对多种乐器动态化。
;with cte
as
(
SELECT * from
(SELECT * FROM @tempMusicSchoolStudent t) x
PIVOT
(MAX(expertise) FOR instrumentname in ([Guitar], [Keyboard])) y
)
SELECT school, studentname,
expertise = case when Guitar is not null then 'Guitar' else NULL end,
Guitar AS instrumentname,
expertise = case when Keyboard is not null then 'Keyboard' else NULL end,
Keyboard AS instrumentname,
count(distinct studentname) AS [DistinctStudentCount]
from cte
group by school,studentname, Guitar, Keyboard
输出:
Foster Jimmy Guitar 5 Keyboard 8 1
Foster Matt Guitar 10 NULL NULL 1
Foster Ryan NULL NULL Keyboard 9 1
Midlothean Kyle NULL NULL Keyboard 10 1
Midlothean Mary Guitar 4 Keyboard 7 1
这是我一直在寻找的解决方案,我不得不使用 unpivot + pivot。
真正让我苦恼的是为要旋转的列选择多个值,而不是最大值。
所以在这种情况下,我希望在给定的 "instrument expertise" 列下有多个 "expertise" 数字。不仅仅是该仪器的最大专业知识。
理解解决方案的第一个关键是 pivot 语句对所选列进行隐式分组。因此,为了在您的透视列下实现多个值,您必须通过包含某种类型的 dense_rank/rank/row_number 来保持您分组的列的完整性。这基本上代表了您正在旋转的列的值的变化,然后被旋转包含在隐式组中,这导致在旋转列中获得多个值,而不仅仅是最大值。
所以在下面的代码中,"expertisenum" 列保持了专业知识数据的完整性。
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255),
expertise INT)
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname, expertise)
SELECT 'Foster','Matt','Guitar','10'
UNION
SELECT 'Foster','Jimmy','Guitar','5'
UNION
SELECT 'Foster','Jimmy','Keyboard','8'
UNION
SELECT 'Foster','Ryan','Keyboard','9'
UNION
SELECT 'Midlothean','Kyle','Keyboard','10'
UNION
SELECT 'Midlothean','Mary','Guitar','4'
UNION
SELECT 'Midlothean','Mary','Keyboard','7'
SELECT school, [Guitar expertise], [Keyboard expertise], COUNT(*) [Count]
FROM
(
SELECT school,[expertiseNum],
CASE WHEN [Columns]='expertise' THEN instrumentname + ' expertise'
END [Columns1], [Values] AS [Values1]
FROM
(
SELECT school, studentname, instrumentname, DENSE_RANK() OVER(PARTITION BY school,instrumentname ORDER BY expertise) AS [expertiseNum],
CONVERT(VARCHAR(255),expertise) AS [expertise]
FROM @tempMusicSchoolStudent
) x
UNPIVOT (
[Values] FOR [Columns] IN ([expertise])
) unpvt
) p
PIVOT (
MAX([Values1]) FOR [Columns1] IN ([Guitar expertise], [Keyboard expertise])
) pvt
GROUP BY school,[Guitar expertise], [Keyboard expertise]