我有一个包含此SubjectID UserID
列的表格。单个用户有许多主题ID。我需要以某种方式选择以获得与此类似的结果集:
UserID1 SubjectID1 SubjectID2 Subject3
UserID2 SubjectID1 SubjectID2 Subject3
UserID3 SubjectID1 SubjectID2 Subject3
答案 0 :(得分:2)
您使用的是哪个数据库? Microsoft SQL Server(2005年起)具有PIVOT / UNPIVOT以将行转置为列,反之亦然。 http://msdn.microsoft.com/en-us/library/ms177410.aspx
答案 1 :(得分:1)
为了便于讨论,我们在名为 SubjectUser 的表中定义样本数据集,如下所示:
SELECT NULL AS SubjectId, NULL AS UserID INTO SubjectUser WHERE 1=0
UNION SELECT 'cpsc500', 'maxt3r'
UNION SELECT 'phil507', 'zontar33'
UNION SELECT 'phil507', 'maxt3r'
UNION SELECT 'eng501', 'zontar33'
UNION SELECT 'eng501', 'maxt3r'
UNION SELECT 'bkwv101', 'spaced99'
然后,您可以使用此查询获得所需的结果:
;WITH
orderedSubjects AS (
SELECT
UserId
, SubjectId
, 'SubjectId'
+ CAST(
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY SubjectId)
AS NVARCHAR )
AS col
FROM SubjectUser
)
SELECT *
FROM orderedSubjects
PIVOT (
MAX(SubjectId)
FOR col IN (SubjectId1, SubjectId2, SubjectId3)
) AS p
让我们来看看这个查询的部分内容。第一个问题是为每个用户的主题分配列名。 orderedSubjects 表用于此目的,由此查询定义:
SELECT
UserId
, SubjectId
, 'SubjectId'
+ CAST(
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY SubjectId)
AS NVARCHAR )
AS col
FROM SubjectUser
ROW_NUMBER()... PARTITION BY ... ORDER BY用于为每个用户的主题分配序列号。任意地,主题按字母顺序排列。然后,通过在每个序列号前加上字符串 SubjectId 来生成列名。结果如下:
UserId SubjectId col
maxt3r cpsc500 SubjectId1
maxt3r eng501 SubjectId2
maxt3r phil507 SubjectId3
spaced99 bkwv101 SubjectId1
zontar33 eng501 SubjectId1
zontar33 phil507 SubjectId2
我们现在拥有创建最终结果所需的数据。它是通过旋转 orderedSubjects :
获得的SELECT *
FROM orderedSubjects
PIVOT (
MAX(SubjectId)
FOR col IN (SubjectId1, SubjectId2, SubjectId3)
) AS p
MAX 的应用只是因为 PIVOT 语法需要使用聚合函数。在目前的情况下,每个组中只有一个 SubjectID ,因此 MAX 可以很容易地 MIN 。
另请注意,SQL Server PIVOT 语法要求生成的数据透视表列的数量固定。在这种情况下,查询是针对三个主题的硬编码。如果数据包含的值多于分配的列数,则会丢弃多余的值。
最终结果如下:
UserId SubjectId1 SubjectId2 SubjectId3
maxt3r cpsc500 eng501 phil507
spaced99 bkwv101 NULL NULL
zontar33 eng501 phil507 NULL