【问题标题】:Transform Columns to Rows dynamically using T-SQL使用 T-SQL 动态地将列转换为行
【发布时间】:2020-11-19 19:44:33
【问题描述】:

我有下表,我需要将列转换为行

tbl_Survey:

      SurveyID   Quest_1  Quest_2  Quest_3
             7        1         1        1
             8        2         2        2
             9        3         3        3
     
 

我需要得到以下结果:

       SurveyID  Questions  Rating 
              7    Quest_1      1
              7    Quest_2      1
              7    Quest_3      1
              8    Quest_1      2
              8    Quest_2      2
              8    Quest_3      2
              9    Quest_1      3
              9    Quest_2      3
              9    Quest_3      3 
    

为了得到这个结果,我使用了以下代码:

       SELECT [SurveyID], [Question], [Rating]
       FROM [dbo].[tbl_Survey]

       UNPIVOT
        (
         [Rating]
          FOR [Question] in ([Quest_1], [Quest_2], [Quest_3])
        ) AS SurveyUnpivot

但是,我的 Quest_1、Quest_2、Quest_3 值可能会更改/甚至添加一个新值...

有没有办法对它们进行编码,所以它可以用于任何文本值(不仅用于 Quest_1 2 3)? 不需要 UNPIVOT... 可以是任何其他方式

谢谢

【问题讨论】:

    标签: sql sql-server tsql dynamic unpivot


    【解决方案1】:

    你需要动态的UNPIVOT。检查以下示例:

    DROP TABLE IF EXISTS [dbo].[DataSource];
    
    CREATE TABLE [dbo].[DataSource]
    (
        [SurveyID] INT
       ,[Quest_1] INT
       ,[Quest_2] INT
       ,[Quest_3] INT
    );
    
    INSERT INTO [dbo].[DataSource] ([SurveyID], [Quest_1], [Quest_2], [Quest_3])
    VALUES (7, 1, 1, 1)
          ,(8, 2, 2, 2)
          ,(9, 3, 3, 3);
    
    GO
    
    DECLARE @DynamicTSQLStatement NVARCHAR(MAX);
    DECLARE @DynamicTSQLUnpivotColumns NVARCHAR(MAX);
    
    SET @DynamicTSQLUnpivotColumns = STUFF
    (
        (
            SELECT ',' + QUOTENAME([name])
            FROM [sys].[columns]
            WHERE [object_id] = OBJECT_ID('[dbo].[DataSource]')
                AND [name] <> 'SurveyID'
            ORDER BY [name]
            FOR XML PATH(''), TYPE
        ).value('.', 'VARCHAR(MAX)')
        ,1
        ,1
        ,''
    );
    
    SET @DynamicTSQLStatement = N'
    SELECT [SurveyID], [Question], [Rating]
    FROM [dbo].[DataSource]
    UNPIVOT
    (
        [Rating] FOR [Question] in (' + @DynamicTSQLUnpivotColumns + ')
    ) AS SurveyUnpivot';
    
    EXEC sp_executesql @DynamicTSQLStatement;
    

    【讨论】:

    • 出于好奇,stuff / xmlstring_agg 好吗?我个人更喜欢string_agg@gotqn
    • @Birel 最好使用STRING_AGG,但由于 SQL Server 2016 及更高版本支持它并且问题不是版本标记,因此我更喜欢显示XML PATH 技术将适用于所有版本。
    【解决方案2】:

    我更喜欢在这里使用联合,因为 PIVOTUNPIVOT 所需的语法很冗长:

    SELECT SurveyID, 'Quest_1' AS Questions, Quest_1 AS Rating FROM tbl_Survey UNION ALL
    SELECT SurveyID, 'Quest_2', Quest_2 FROM tbl_Survey UNION ALL
    SELECT SurveyID, 'Quest_3', Quest_3 FROM tbl_Survey
    ORDER BY SurveyID, Rating;
    

    【讨论】:

    • 我将尝试您的查询。但是 - 仍然看不到我的问题的解决方案(例如,如果我的表中有“Quest_4545”或“ttt4444”而不是 Quest_1 怎么办?在这种情况下,每次值更改时我都必须更新代码是t-sql 中有什么方法 - 避免每次我更新值时更改代码而不是我当前的“Quest_1”“Quest_2”“Quest_3”?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-20
    • 2014-04-13
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多