没有笛卡尔结果的T-SQL多个数据透视语句

时间:2016-09-18 02:54:33

标签: sql-server tsql pivot

我有下面的T-SQL语句,我试图转向2个不同的数据元素,studentname和instrumentname。结果应该是每个学校只有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

糟糕的结果截图:

enter image description here

我希望结果看起来像这样:

enter image description here

2 个答案:

答案 0 :(得分: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'



;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

结果: enter image description here

答案 1 :(得分:1)

UNPIVOT + PIVOT +两个DENSE_RANK s:

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数据并将学生与两个序列的序列号和乐器连接起来,因为如果我们只使用乐器序列 - 学生拥有该乐器或其第一(或第二)乐器之间将没有链接。