【问题标题】:SQL - Multiple Rows to Columns - Pivot? Cross Table?SQL - 多行到列 - 枢轴?交叉表?
【发布时间】:2021-05-19 16:20:48
【问题描述】:

我有一个包含以下结果的表(来自 SQL 查询)

ID Type Comment
12345 Manager Comment This is a Manager comment
12345 HR Comment This is a HR comment
12345 HR Comment This is another HR comment
54321 Manager Comment This is a Manager comment
54321 Manager Comment This is another Manager comment
54321 Manager Comment This is another Manager comment aswell

我正在尝试让输出看起来像这样:

ID Manager Comment 1 Manager Comment 2 Manager Comment 3 HR Comment 1 HR Comment 2
12345 This is a HR comment This is a HR comment This is another HR Comment
54321 This is a Manager comment This is another Manager comment This is another Manager comment aswell

这个 cmets 的数量可以在 0 到 5 之间变化。

我尝试了以下方法,但它仅适用于每个部分中的最新 cmets:

SELECT *
FROM
(
    SELECT
        A.[SHIFTASSIGNID] as 'ID'
        ,c.[COMMENTTEXT] as 'Comment Type'
        ,b.COMNTNOTETXT as 'Comment'

      FROM [tkcsdb].[dbo].[SHFTASGNCOMNTMM] A 
      join [tkcsdb].[dbo].[COMNTNOTEDTL] B on
      a.[COMNTNOTEID] = b.[COMNTNOTEID]

      join [tkcsdb].[dbo].[COMMENTS] C
      on c.commentID = a.commentID
        where A.SHIFTASSIGNID = 7354246
) AS SourceTable PIVOT(max([Comment]) FOR [Type] IN([HR Notes],[Manager Notes], [Kommentar])) AS PivotTable;

显然它不能容纳多人 cmets,我已经花了大约 3 个小时在这方面,所以任何帮助将不胜感激。

谢谢 克里斯

【问题讨论】:

  • 标记你的数据库
  • 我认为您必须创建一个 row_number 列,然后将 rownumber 连接到评论类型字段。如果 cmets 的数量是动态的,那么您将需要一个动态枢轴。我实际上只是回答了一个问题。 stackoverflow.com/questions/67580698/…
  • 你为什么要这样做? (如果 cmets 的数量是可变的,那么最适合在 SQL 中使用的结构就是您已经拥有的结构。如果您要旋转数据以向人类展示,请在您的展示层/应用程序中执行此操作,不要' t 用 SQL 来做。这是一种 SQL 反模式/代码气味。)

标签: sql


【解决方案1】:

请参阅最后的工作 示例。在示例中,我给 cmets 一个日期,以便可以对它们进行相应的排序。

我在做什么:

我正在为每个评论文本添加一个行号,以便 Manager Comment 变为 Manager Comment 1Manager Comment 2,具体取决于行号。

既然我们知道每种类型最多有五个 cmets,我们可以简单地在 PIVOT 中询问所有这些 cmets

SELECT
  *
FROM (
  SELECT
    A.[SHIFTASSIGNID] AS 'ID'
   ,C.[COMMENTTEXT] + ' ' + CONVERT(NVARCHAR(20), ROW_NUMBER() OVER (PARTITION BY A.[SHIFTASSIGNID], C.[COMMENTTEXT] ORDER BY (SELECT NULL))) AS 'Comment Type'
   ,B.COMNTNOTETXT    AS 'Comment'

  FROM [tkcsdb].[dbo].[SHFTASGNCOMNTMM] A
  JOIN [tkcsdb].[dbo].[COMNTNOTEDTL] B
    ON A.[COMNTNOTEID] = B.[COMNTNOTEID]

  JOIN [tkcsdb].[dbo].[COMMENTS] C
    ON C.commentID = A.commentID
  WHERE
    A.SHIFTASSIGNID = 7354246
) AS SourceTable PIVOT (MAX([Comment]) FOR [Comment Type] IN ([Manager Comment 1], [Manager Comment 2], [Manager Comment 3], [Manager Comment 4], [Manager Comment 5], 
                                                      [HR Comment 1], [HR Comment 2], [HR Comment 3], [HR Comment 4], [HR Comment 5])) AS PivotTable;

工作示例:

SELECT
  12345                       AS 'ID'
 ,'Manager Comment'           AS 'Type'
 ,'This is a Manager comment' AS 'Comment'
 ,CONVERT(DATE, '2021-01-01') AS 'Date'
INTO #COMMENTS
UNION ALL
SELECT
  12345                       AS 'ID'
 ,'HR Comment'                AS 'Type'
 ,'This is a HR comment'      AS 'Comment'
 ,CONVERT(DATE, '2020-01-01') AS 'Date'
UNION ALL
SELECT
  12345                        AS 'ID'
 ,'HR Comment'                 AS 'Type'
 ,'This is another HR comment' AS 'Comment'
 ,CONVERT(DATE, '2021-01-01')  AS 'Date'
UNION ALL
SELECT
  54321                       AS 'ID'
 ,'Manager Comment'           AS 'Type'
 ,'This is a Manager comment' AS 'Comment'
 ,CONVERT(DATE, '2021-01-01') AS 'Date'
UNION ALL
SELECT
  54321                             AS 'ID'
 ,'Manager Comment'                 AS 'Type'
 ,'This is another Manager comment' AS 'Comment'
 ,CONVERT(DATE, '2020-01-01')       AS 'Date'
UNION ALL
SELECT
  54321                                    AS 'ID'
 ,'Manager Comment'                        AS 'Type'
 ,'This is another Manager comment aswell' AS 'Comment'
 ,CONVERT(DATE, '2019-01-01')              AS 'Date';



SELECT
  *
FROM (
  SELECT
    #COMMENTS.ID      AS 'ID'
   ,#COMMENTS.type + ' ' + CONVERT(NVARCHAR(20), ROW_NUMBER() OVER (PARTITION BY #COMMENTS.ID, #COMMENTS.type ORDER BY #COMMENTS.DATE ASC)) AS 'Comment Type'
   ,#COMMENTS.Comment AS 'Comment'

  FROM #COMMENTS
) AS SourceTable PIVOT (MAX([Comment]) FOR [Comment Type] IN ([Manager Comment 1], [Manager Comment 2], [Manager Comment 3], [Manager Comment 4], [Manager Comment 5],
[HR Comment 1], [HR Comment 2], [HR Comment 3], [HR Comment 4], [HR Comment 5])) AS PivotTable;



DROP TABLE #COMMENTS


【讨论】:

    【解决方案2】:

    只有当您知道或想要限制评论栏的数量时,我的其他答案才有效。通过这个答案,我将演示如何对任意数量的 cmets 执行此操作。

    为此,您必须动态创建列标题并使用EXEC()PIVOT 查询作为字符串执行

    SELECT
      12345 AS 'ID'
     ,'Manager Comment' AS 'Type'
     ,'This is a Manager comment' AS 'Comment'
     ,CONVERT(DATE, '2021-01-01') AS 'Date' INTO Comments
    UNION ALL
    SELECT
      12345 AS 'ID'
     ,'HR Comment' AS 'Type'
     ,'This is a HR comment' AS 'Comment'
     ,CONVERT(DATE, '2020-01-01') AS 'Date'
    UNION ALL
    SELECT
      12345 AS 'ID'
     ,'HR Comment' AS 'Type'
     ,'This is another HR comment' AS 'Comment'
     ,CONVERT(DATE, '2021-01-01') AS 'Date'
    UNION ALL
    SELECT
      54321 AS 'ID'
     ,'Manager Comment' AS 'Type'
     ,'This is a Manager comment' AS 'Comment'
     ,CONVERT(DATE, '2021-01-01') AS 'Date'
    UNION ALL
    SELECT
      54321 AS 'ID'
     ,'Manager Comment' AS 'Type'
     ,'This is another Manager comment' AS 'Comment'
     ,CONVERT(DATE, '2020-01-01') AS 'Date'
    UNION ALL
    SELECT
      54321 AS 'ID'
     ,'Manager Comment' AS 'Type'
     ,'This is another Manager comment aswell' AS 'Comment'
     ,CONVERT(DATE, '2019-01-01') AS 'Date';
    
    DECLARE @cols NVARCHAR(MAX) = '';
    
    DECLARE @SQL NVARCHAR(MAX) = 'SELECT *
    FROM (SELECT
        Comments.id AS ID
       ,Comments.type + SPACE(1) + CONVERT(NVARCHAR(20), ROW_NUMBER() OVER (PARTITION BY Comments.id, Comments.type ORDER BY Comments.DATE ASC)) AS CommentType
       ,Comments.Comment AS Comment
    
      FROM Comments) AS SourceTable PIVOT (MAX([Comment]) FOR [CommentType] IN (##COLUMNS##)) AS PivotTable;';
    
    
    WITH COMMENTS1 AS
    (
    SELECT
    Comments.id AS ID
     ,Comments.type + SPACE(1) + CONVERT(NVARCHAR(20), ROW_NUMBER() OVER (PARTITION BY Comments.id, Comments.type ORDER BY Comments.DATE ASC)) AS CommentType
     ,Comments.Comment AS Comment
    
    FROM Comments
    ),
    DISTINCT_COMMENTS AS
    (
      SELECT DISTINCT CommentType
      FROM COMMENTS1
    )
    SELECT
    @COLS = STRING_AGG('[' + DISTINCT_COMMENTS.CommentType + ']', ',')
    FROM DISTINCT_COMMENTS;
    
    SET @SQL = REPLACE(@SQL, '##COLUMNS##', @COLS);
    
    EXEC(@SQL);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 1970-01-01
      • 2021-06-25
      相关资源
      最近更新 更多