T-SQL 没有笛卡尔结果的多个主元语句
T-SQL multiple pivot statements without cartesian result
我在下面的 T-SQL 语句中尝试以 2 个不同的数据元素(学生姓名和仪器名称)为中心。每个学校的结果应该只有 1 行,学生应该与他们的乐器一起在顶部旋转。
不幸的是,我得到了各种各样的笛卡尔结果,其中学生和仪器跨越多行(查询后见屏幕截图)。我怎样才能像我想要的那样只在每所学校获得一行?
查询:
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255))
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname)
SELECT 'Foster','Matt','Guitar'
UNION
SELECT 'Foster','Matt','Violin'
UNION
SELECT 'Foster','Jenny','Keyboard'
UNION
SELECT 'Midlothean','Kyle','Drums'
UNION
SELECT 'Midlothean','Mary','Piano'
UNION
SELECT 'Midlothean','Mary','Trumpet'
SELECT
p1.school, [Student1], [Instrument1], [Instrument2], [Student2], [Instrument1], [Instrument2]
FROM
(SELECT
school, studentname, instrumentname,
'Student' + CONVERT(VARCHAR(255),
DENSE_RANK() OVER(PARTITION BY school ORDER BY studentname)) [StudentNum],
'Instrument' + CONVERT(VARCHAR(255),ROW_NUMBER() OVER(PARTITION BY school, studentname ORDER BY instrumentname)) AS [InstrumentNum]
FROM
@tempMusicSchoolStudent) src
PIVOT
(MAX(studentname) FOR [StudentNum] IN ([Student1], [Student2])) p
PIVOT
(
MAX([instrumentname])
FOR [InstrumentNum] IN ([Instrument1],[Instrument2])
) p1
ORDER BY p1.school
错误的结果截图:
我希望结果如下所示:
这可行,但有点乱,尤其是动态创建,我希望有一个更简洁的选项。我什至想不出如何用案例陈述来做到这一点,不确定那是否会更干净。如果有人有更清晰、更易读的解决方案,正确的答案仍然有待解决。谢谢
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255))
INSERT INTO @tempMusicSchoolStudent(school,studentname, instrumentname)
SELECT 'Foster','Matt','Guitar'
UNION
SELECT 'Foster','Matt','Violin'
UNION
SELECT 'Foster','Jenny','Keyboard'
UNION
SELECT 'Midlothean','Kyle','Drums'
UNION
SELECT 'Midlothean','Mary','Piano'
UNION
SELECT 'Midlothean','Mary','Trumpet'
;WITH studentPivot AS
(
SELECT p1.school,[Student1],[Student2]
FROM
(
SELECT school, studentname,
'Student' + CONVERT(VARCHAR(255),DENSE_RANK() OVER(PARTITION BY school ORDER BY studentname)) [StudentNum]
FROM @tempMusicSchoolStudent
) src
PIVOT
(
MAX(studentname)
FOR [StudentNum] IN ([Student1],[Student2])
) p1
),
instrumentPivot AS
(
SELECT p1.studentname,[Instrument1],[Instrument2]
FROM
(
SELECT school, studentname, instrumentname,
'Instrument' + CONVERT(VARCHAR(255),ROW_NUMBER() OVER(PARTITION BY school,studentname ORDER BY instrumentname)) AS [InstrumentNum]
FROM @tempMusicSchoolStudent
) src
PIVOT
(
MAX(instrumentname)
FOR [InstrumentNum] IN ([Instrument1],[Instrument2])
) p1
)
SELECT sp.school,sp.Student1,ip.Instrument1,ip.Instrument2,sp.Student2,ip1.Instrument1,ip1.Instrument2
FROM studentPivot sp
JOIN instrumentPivot ip ON ip.studentname=sp.Student1
JOIN instrumentPivot ip1 ON ip1.studentname=sp.Student2
结果:
UNPIVOT + PIVOT + two DENSE_RANKs:
SELECT *
FROM (
SELECT school,
CASE WHEN [Columns] = 'student' THEN [Columns] + StSeq
WHEN [Columns] = 'instrument' THEN [Columns] + StSeq + InSeq
ELSE NULL END as [Columns],
[Values]
FROM (
SELECT school,
CAST(studentname as varchar(255)) student,
instrumentname as instrument,
CAST(DENSE_RANK() OVER (PARTITION BY school ORDER BY studentname) as nvarchar(2)) as StSeq,
CAST(DENSE_RANK() OVER (PARTITION BY school,studentname ORDER BY instrumentname) as nvarchar(2)) as InSeq
FROM @tempMusicSchoolStudent
) t
UNPIVOT (
[Values] FOR [Columns] IN (student,instrument)
) unpvt
) p
PIVOT (
MAX([Values]) FOR [Columns] IN (student1,instrument11,instrument12,student2,instrument21,instrument22)
) pvt
输出:
school student1 instrument11 instrument12 student2 instrument21 instrument22
Foster Jenny Keyboard NULL Matt Guitar Violin
Midlothean Kyle Drums NULL Mary Piano Trumpet
主要思想是为学生和乐器获得2个序列。比 UNPIVOT 数据并将学生与序列号和仪器与两个序列连接起来,因为如果我们仅使用仪器序列 - 将没有 link 在哪个学生拥有该仪器或谁的第一个(或第二个)仪器是.
我在下面的 T-SQL 语句中尝试以 2 个不同的数据元素(学生姓名和仪器名称)为中心。每个学校的结果应该只有 1 行,学生应该与他们的乐器一起在顶部旋转。
不幸的是,我得到了各种各样的笛卡尔结果,其中学生和仪器跨越多行(查询后见屏幕截图)。我怎样才能像我想要的那样只在每所学校获得一行?
查询:
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255))
INSERT INTO @tempMusicSchoolStudent(school, studentname, instrumentname)
SELECT 'Foster','Matt','Guitar'
UNION
SELECT 'Foster','Matt','Violin'
UNION
SELECT 'Foster','Jenny','Keyboard'
UNION
SELECT 'Midlothean','Kyle','Drums'
UNION
SELECT 'Midlothean','Mary','Piano'
UNION
SELECT 'Midlothean','Mary','Trumpet'
SELECT
p1.school, [Student1], [Instrument1], [Instrument2], [Student2], [Instrument1], [Instrument2]
FROM
(SELECT
school, studentname, instrumentname,
'Student' + CONVERT(VARCHAR(255),
DENSE_RANK() OVER(PARTITION BY school ORDER BY studentname)) [StudentNum],
'Instrument' + CONVERT(VARCHAR(255),ROW_NUMBER() OVER(PARTITION BY school, studentname ORDER BY instrumentname)) AS [InstrumentNum]
FROM
@tempMusicSchoolStudent) src
PIVOT
(MAX(studentname) FOR [StudentNum] IN ([Student1], [Student2])) p
PIVOT
(
MAX([instrumentname])
FOR [InstrumentNum] IN ([Instrument1],[Instrument2])
) p1
ORDER BY p1.school
错误的结果截图:
我希望结果如下所示:
这可行,但有点乱,尤其是动态创建,我希望有一个更简洁的选项。我什至想不出如何用案例陈述来做到这一点,不确定那是否会更干净。如果有人有更清晰、更易读的解决方案,正确的答案仍然有待解决。谢谢
DECLARE @tempMusicSchoolStudent TABLE
(school VARCHAR(50),
studentname VARCHAR(50),
instrumentname VARCHAR(255))
INSERT INTO @tempMusicSchoolStudent(school,studentname, instrumentname)
SELECT 'Foster','Matt','Guitar'
UNION
SELECT 'Foster','Matt','Violin'
UNION
SELECT 'Foster','Jenny','Keyboard'
UNION
SELECT 'Midlothean','Kyle','Drums'
UNION
SELECT 'Midlothean','Mary','Piano'
UNION
SELECT 'Midlothean','Mary','Trumpet'
;WITH studentPivot AS
(
SELECT p1.school,[Student1],[Student2]
FROM
(
SELECT school, studentname,
'Student' + CONVERT(VARCHAR(255),DENSE_RANK() OVER(PARTITION BY school ORDER BY studentname)) [StudentNum]
FROM @tempMusicSchoolStudent
) src
PIVOT
(
MAX(studentname)
FOR [StudentNum] IN ([Student1],[Student2])
) p1
),
instrumentPivot AS
(
SELECT p1.studentname,[Instrument1],[Instrument2]
FROM
(
SELECT school, studentname, instrumentname,
'Instrument' + CONVERT(VARCHAR(255),ROW_NUMBER() OVER(PARTITION BY school,studentname ORDER BY instrumentname)) AS [InstrumentNum]
FROM @tempMusicSchoolStudent
) src
PIVOT
(
MAX(instrumentname)
FOR [InstrumentNum] IN ([Instrument1],[Instrument2])
) p1
)
SELECT sp.school,sp.Student1,ip.Instrument1,ip.Instrument2,sp.Student2,ip1.Instrument1,ip1.Instrument2
FROM studentPivot sp
JOIN instrumentPivot ip ON ip.studentname=sp.Student1
JOIN instrumentPivot ip1 ON ip1.studentname=sp.Student2
结果:
UNPIVOT + PIVOT + two DENSE_RANKs:
SELECT *
FROM (
SELECT school,
CASE WHEN [Columns] = 'student' THEN [Columns] + StSeq
WHEN [Columns] = 'instrument' THEN [Columns] + StSeq + InSeq
ELSE NULL END as [Columns],
[Values]
FROM (
SELECT school,
CAST(studentname as varchar(255)) student,
instrumentname as instrument,
CAST(DENSE_RANK() OVER (PARTITION BY school ORDER BY studentname) as nvarchar(2)) as StSeq,
CAST(DENSE_RANK() OVER (PARTITION BY school,studentname ORDER BY instrumentname) as nvarchar(2)) as InSeq
FROM @tempMusicSchoolStudent
) t
UNPIVOT (
[Values] FOR [Columns] IN (student,instrument)
) unpvt
) p
PIVOT (
MAX([Values]) FOR [Columns] IN (student1,instrument11,instrument12,student2,instrument21,instrument22)
) pvt
输出:
school student1 instrument11 instrument12 student2 instrument21 instrument22
Foster Jenny Keyboard NULL Matt Guitar Violin
Midlothean Kyle Drums NULL Mary Piano Trumpet
主要思想是为学生和乐器获得2个序列。比 UNPIVOT 数据并将学生与序列号和仪器与两个序列连接起来,因为如果我们仅使用仪器序列 - 将没有 link 在哪个学生拥有该仪器或谁的第一个(或第二个)仪器是.