简体   繁体   English

根据排名号将单列拆分为多列

[英]Split single column into multiple columns based on Rank Number

I want to spit a column into multiple columns based on the rank by partition or column type我想根据分区或列类型的排名将一列分成多列

Sample Input Data:样本输入数据:

STUDENT     PROGRAM_ID      DEG_TYPE    PROGRAM_RN
  1         Program1.MA     MA          1
  1         Program2.MA     MA          1
  2         Program1.PHD    DOC         1
  2         Program2.MA     MA          2
  3         Program.CERT    CERT        3
  3         Program1.PSYD   DOC         1
  3         Program2.MA     MA          2

Expected Output预计 Output

Student        Highest Program            Second Highest Program     Third Highest Program
 1             Program1.MA, Program2.MA     
 2             Program1.PSYD               Program2.MA  
 3             Program1.PHD                Program2.MA                Program.CERT

I have tried using PIVOT and I am able to split the column but with that I am able to fetch only one program as Highest, second and so on.我已经尝试使用 PIVOT 并且我能够拆分列,但是我只能获取一个程序作为最高、第二等等。 My requirement is to get all the Programs that has RN 1 listed for each student in highest program, all with RN 2 listed in Second and so on.我的要求是在最高课程中为每个学生列出 RN 1 的所有课程,所有课程都在第二课程中列出 RN 2,依此类推。

**CODE**
  SELECT [STUDENTS_ID],[1], [2], [3]
  FROM
  (SELECT [STUDENTS_ID]
  ,[PROGRAM_ID]
  ,[PROGRAM_RN]
   FROM [dbo].[CTE] ) AS SourceTable
   PIVOT
   (
   MAX([PROGRAM_ID])
   FOR [PROGRAM_RN] IN ([1], [2], [3])
   ) As PivotTable;

Current Output当前Output

Student     Highest Program     Second Highest Program  Third Highest Program
 1          Program1.MA         
 2          Program1.PSYD       Program2.MA 
 3          Program1.PHD        Program2.MA                  Program.CERT

I also want to know if there is a better way of doing this我也想知道是否有更好的方法来做到这一点

If you are using SQL 2017 or higher version, you can use string_agg function instead of XML PATH in below query else you can use the same query to dynamically achieve the result set you want.如果您使用的是 SQL 2017 或更高版本,则可以使用 string_agg function 而不是 XML PATH 在下面的查询中您想要动态实现相同的查询结果集。

DECLARE @Columns   AS NVARCHAR(MAX),
        @Query     AS NVARCHAR(MAX)
SET @Columns = STUFF((SELECT DISTINCT ',' + QUOTENAME(c.PROGRAM_RN)
               FROM StudentTable c
               FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET @Query = 'SELECT STUDENT, ' + @Columns + ' FROM 
              (
                SELECT DISTINCT ST2.STUDENT ,PROGRAM_RN,
                SUBSTRING(
                (
                    SELECT '', ''+ST1.PROGRAM_ID  AS [text()]
                    FROM dbo.StudentTable ST1
                    WHERE ST1.STUDENT = ST2.STUDENT AND ST1.PROGRAM_RN = ST2.PROGRAM_RN
                    ORDER BY ST1.STUDENT
                    FOR XML PATH ('''')
                ), 2, 1000) [PROGRAM_ID]
                FROM dbo.StudentTable ST2
              ) x
              PIVOT 
              (
                 MAX(PROGRAM_ID)
                 FOR PROGRAM_RN IN (' + @Columns + ')
              ) p '
EXEC(@Query)

Sort of odd that you have ties.有点奇怪,你有关系。 But you can use conditional aggregation with strings:但是您可以对字符串使用条件聚合:

select student,
       string_agg(case when program_rn = 1 then program_id end, ', '),
       string_agg(case when program_rn = 2 then program_id end, ', '),
       string_agg(case when program_rn = 3 then program_id end, ', ')
from t
group by student;

If you know the maximum that need to be concatenated, you can use conditional aggregation:如果您知道需要连接的最大值,则可以使用条件聚合:

select student,
       concat(max(case when program_rn = 1 and seqnum = 1 then program_id + '; ' end),
              max(case when program_rn = 1 and seqnum = 2 then program_id + '; ' end),
              max(case when program_rn = 1 and seqnum = 3 then program_id + '; ' end)
             ),
       concat(max(case when program_rn = 2 and seqnum = 1 then program_id + '; ' end),
              max(case when program_rn = 2 and seqnum = 2 then program_id + '; ' end),
              max(case when program_rn = 2 and seqnum = 3 then program_id + '; ' end)
             ),
       concat(max(case when program_rn = 3 and seqnum = 1 then program_id + '; ' end),
              max(case when program_rn = 3 and seqnum = 2 then program_id + '; ' end),
              max(case when program_rn = 3 and seqnum = 3 then program_id + '; ' end)
             ),
from (select t.*,
             row_number() over (partition by student, program_rn order by program_id) as seqnum
      from t
     ) t
group by student;

This is cumbersome, but possibly simpler than FOR XML PATH .这很麻烦,但可能比FOR XML PATH更简单。

Note that I changed the delimiter to a semicolon, because that seems more natural for leaving it at the end of the list.请注意,我将分隔符更改为分号,因为将其留在列表末尾似乎更自然。 Although it can be removed, that just further complicates the logic, perhaps unnecessarily.尽管可以将其删除,但这只会使逻辑更加复杂,也许是不必要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM