开发者

Selecting from a flat table

I've got a table with columns like this SubjectID UserID. There are many subjectIDs f开发者_Python百科or a single user. I need to do select somehow to get a result set similar to this:

UserID1 SubjectID1 SubjectID2 Subject3
UserID2 SubjectID1 SubjectID2 Subject3
UserID3 SubjectID1 SubjectID2 Subject3


Which Database are you using ? Microsoft SQL Server (2005 onwards) has PIVOT/UNPIVOT to transpose Rows to columns and vice versa. http://msdn.microsoft.com/en-us/library/ms177410.aspx


For purposes of discussion, let's define a sample dataset in a table called SubjectUser as follows:

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'

You can then get the desired result using this query:

;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

Let's look at this query in parts. The first problem is to assign column names to each user's subjects. The orderedSubjects table serves this purpose, defined by this query:

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 is used to assign a sequence number to each user's subjects. Arbitrarily, the subjects are ordered alphabetically. Then, a column name is generated by prefixing each sequence number with the string SubjectId. The result is as follows:

UserId     SubjectId   col
maxt3r     cpsc500     SubjectId1
maxt3r     eng501      SubjectId2
maxt3r     phil507     SubjectId3
spaced99   bkwv101     SubjectId1
zontar33   eng501      SubjectId1
zontar33   phil507     SubjectId2

We now have the data we need to create the final result. It is obtained by pivoting orderedSubjects:

SELECT *
FROM orderedSubjects
PIVOT (
  MAX(SubjectId)
  FOR col IN (SubjectId1, SubjectId2, SubjectId3)
) AS p

The application of the MAX is necessary only because the PIVOT syntax requires the use of an aggregation function. In the case at hand, there is only one SubjectID in each group, so MAX could just as easily have been MIN.

Also note that the SQL Server PIVOT syntax demands that the set of generated pivot columns be fixed in number. In this case, the query is hard-coded for three subjects. If the data contains more values than will fit into the allocated number of columns, the excess are discarded.

The final result is as follows:

UserId      SubjectId1      SubjectId2      SubjectId3
maxt3r      cpsc500         eng501          phil507
spaced99    bkwv101         NULL            NULL
zontar33    eng501          phil507         NULL
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜