【问题标题】:Transpose a set of rows as columns in SQL Server 2000在 SQL Server 2000 中将一组行转换为列
【发布时间】:2010-09-14 05:52:15
【问题描述】:

在 SQL Server 中是否有任何将行转换为列的工具(在 MS-Access 中可以)? 我很困惑,因为这个工具在 MS-Access 中可用,但在 SQL Server 中不可用。 SQL Server 中没有包含此功能是设计使然吗?

【问题讨论】:

    标签: sql-server pivot


    【解决方案1】:

    http://jdixon.dotnetdevelopersjournal.com/pivot_table_data_in_sql_server_2000_and_2005.htm 的示例仅在您事先知道行值可以是什么时才有效。例如,假设您有一个具有自定义属性的实体,并且自定义属性被实现为子表中的行,其中子表基本上是变量/值对,并且这些变量/值对是可配置的。

    color red
    size  big
    city  Chicago
    

    我将描述一种有效的技术。我用过。我不是在宣传它,但它确实有效。

    要在您事先不知道值是什么的情况下对数据进行透视,请即时创建一个没有列的临时表。然后使用游标遍历您的行,为每个变量发布一个动态构建的“更改表”,以便最终您的临时表具有列、颜色、大小、城市。

    然后您在临时表中插入一行,通过另一个游标通过变量、值对更新它,然后选择它,通常与其父实体连接,实际上使这些自定义变量/值对看起来像是就像原始父实体中的内置列一样。

    【讨论】:

      【解决方案2】:

      所描述的游标方法可能是最不类似于 SQL 的方法。如前所述,SQL 2005 及更高版本的 PIVOT 效果很好。但是对于旧版本和非 MS SQL 服务器,“优化 Transact-SQL”中的 Rozenshtein 方法(编辑:绝版,但可以从亚马逊获得:http://www.amazon.com/Optimizing-Transact-SQL-Advanced-Programming-Techniques/dp/0964981203)非常适合透视和反透视数据。 它使用点特征将基于行的数据转换为列。 Rozenshtein 描述了几种情况,这里是一个例子:

      SELECT
          RowValueNowAColumn = 
             CONVERT(varchar,
                 MAX(
                SUBSTRING(myTable.MyVarCharColumn,1,DATALENGTH(myTable.MyVarCharColumn)
             * CHARINDEX(sa.SearchAttributeName,'MyRowValue'))))
      FROM
          myTable
      

      这种方法比使用 case 语句更有效,并且适用于各种数据类型和 SQL 实现(不仅仅是 MS SQL)。

      【讨论】:

        【解决方案3】:

        关于sql server 2005中的UNPIVOT,我找到了一篇不错的文章

        columns-to-rows-in-sql-server

        【讨论】:

          【解决方案4】:

          这类事情最好限制在小范围内。如果您使用的是 SQL 2k 并且没有可用的 PIVOT 功能,我已经起草了一个应该为您完成这项工作的存储过程。有点拙劣的匆忙工作,所以尽可能多地拆开它。将以下内容粘贴到 sql 窗口中,并根据需要编辑底部的 EXEC。如果你想看看生成了什么,去掉中间的--s:

          IF EXISTS (SELECT * FROM SYSOBJECTS WHERE XTYPE = 'P' AND NAME = 'USP_LIST_CONCAT')
          DROP PROCEDURE USP_LIST_CONCAT
          GO
          
          CREATE PROCEDURE USP_LIST_CONCAT (@SourceTable NVARCHAR(1000) = '' ,@SplitColumn NVARCHAR(1000) = '' , @Deli NVARCHAR(10) = '', @KeyColumns NVARCHAR(2000) = '' , @Condition NVARCHAR(1000) = '')
          AS
          BEGIN
          SET NOCOUNT ON
          
          /* PROCEDURE CREATED 2010 FOR SQL SERVER 2000. SIMON HUGHES. */
          /* NOTES: REMOVE --'s BELOW TO LIST GENERATED SQL. */
          
          IF @SourceTable = '' OR @SourceTable = '?' OR @SourceTable = '/?' OR @SplitColumn = '' OR @KeyColumns = ''
          BEGIN
          PRINT 'Format for use:'
          PRINT ' USP_LIST_CONCAT ''SourceTable'', ''SplitColumn'', ''Deli'', ''KeyColumn1,...'', ''Column1 = 12345 AND ...'''
          PRINT ''
          PRINT 'Description:'
          PRINT 'The SourceTable should contain a number of records acting as a list of values.'
          PRINT 'The SplitColumn should be the name of the column holding the values wanted.'
          PRINT 'The Delimiter may be any single character or string ie ''/'''
          PRINT 'The KeyColumn may contain a comma separated list of columns that will be returned before the concatenated list.'
          PRINT 'The optional Conditions may be left blank or may include the following as examples:'
          PRINT ' ''Column1 = 12334 AND (Column2 = ''ABC'' OR Column3 = ''DEF'')'''
          PRINT ''
          PRINT 'A standard list in the format:'
          PRINT ' Store1, Employee1, Rabbits'
          PRINT ' Store1, Employee1, Dogs'
          PRINT ' Store1, Employee1, Cats'
          PRINT ' Store1, Employee2, Dogs'
          PRINT ''
          PRINT 'Will be returned as:'
          PRINT ' Store1, Employee1, Cats/Dogs/Rabbits'
          PRINT ' Store1, Employee2, Dogs'
          PRINT ''
          PRINT 'A full ORDER BY and DISTINCT is included'
          RETURN -1
          END
          
          
          DECLARE @SQLStatement NVARCHAR(4000)
          
          SELECT @SQLStatement = '
          DECLARE @DynamicSQLStatement NVARCHAR(4000)
          
          SELECT @DynamicSQLStatement = ''SELECT '+@KeyColumns+', SUBSTRING(''
          
          SELECT @DynamicSQLStatement = @DynamicSQLStatement + '' + '' + CHAR(10) +
          '' MAX(CASE WHEN '+@SplitColumn+' = ''''''+RTRIM('+@SplitColumn+')+'''''' THEN '''''+@Deli+'''+RTRIM('+@SplitColumn+')+'''''' ELSE '''''''' END)''
          FROM '+ @SourceTable +' ORDER BY '+@SplitColumn+'
          
          SELECT @DynamicSQLStatement = @DynamicSQLStatement + '' ,2,7999) List'' + CHAR(10) + ''FROM '+ @SourceTable+''' + CHAR(10) +'''+CASE WHEN @Condition = '' THEN '/* WHERE */' ELSE 'WHERE '+@Condition END+ '''+ CHAR(10) + ''GROUP BY '+@KeyColumns+'''
          
          SELECT @DynamicSQLStatement = REPLACE(@DynamicSQLStatement,''( +'',''('')
          
          -- SELECT @DynamicSQLStatement -- DEBUG ONLY
          EXEC (@DynamicSQLStatement)'
          
          EXEC (@SQLStatement)
          
          END
          GO
          
          EXEC USP_LIST_CONCAT 'MyTableName', 'ColumnForListing', 'Delimiter', 'KeyCol1, KeyCol2', 'Column1 = 123456'
          

          【讨论】:

            【解决方案5】:

            我有以下格式的数据

            Survey_question_ID

            电子邮件(用户

            回答

            对于 1 项调查,有 13 个问题和答案 我想要的输出是

            用户 ---Survey_question_ID1---Survey_question_ID2

            电子邮件---回答---回答 ........等等

            这里是SQL Server 2000的解决方案,原因字段数据类型是TEXT

            DROP TABLE #tmp
            
            DECLARE @tmpTable  TABLE
            (
            emailno NUMERIC,
            question1 VARCHAR(80),
            question2 VARCHAR(80),
            question3 VARCHAR(80),
            question4 VARCHAR(80),
            question5 VARCHAR(80),
            question6 VARCHAR(80),
            question7 VARCHAR(80),
            question8 VARCHAR(80),
            question9 VARCHAR(80),
            question10 VARCHAR(80),
            question11 VARCHAR(80),
            question12 VARCHAR(80),
            question13 VARCHAR(8000)
            )
            
            DECLARE @tmpTable2  TABLE
            (
            emailNumber NUMERIC
            )
            
            DECLARE @counter INT
            DECLARE @Email INT
            
            SELECT @counter =COUNT(DISTINCT ans.email) FROM answers ans WHERE ans.surveyname=100430 AND ans.qnpkey BETWEEN 233702 AND 233714
            SELECT * INTO #tmp FROM @tmpTable
            INSERT INTO @tmpTable2 (emailNumber) SELECT DISTINCT CAST(ans.email AS NUMERIC) FROM answers ans WHERE ans.surveyname=100430 AND ans.qnpkey BETWEEN 233702 AND 233714
            
            WHILE @counter >0
            
            BEGIN
            
                    SELECT TOP 1 @Email= emailNumber FROM @tmpTable2
                    INSERT INTO @tmpTable (emailno) VALUES (@Email )
            
            
                    Update @tmpTable set question1=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233702 and ans.email=@Email
                    Update @tmpTable set question2=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233703 and email=@email
                    Update @tmpTable set question3=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233704 and email=@email
                    Update @tmpTable set question4=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233705 and email=@email
                    Update @tmpTable set question5=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233706 and email=@email
                    Update @tmpTable set question6=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233707 and email=@email
                    Update @tmpTable set question7=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233708 and email=@email
                    Update @tmpTable set question8=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233709 and email=@email
                    Update @tmpTable set question9=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233710 and email=@email
                    Update @tmpTable set question10=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233711 and email=@email
                    Update @tmpTable set question11=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233712 and email=@email
                    Update @tmpTable set question12=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233713 and email=@email
                    Update @tmpTable set question13=CAST(answer as VARCHAR(8000)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233714 and email=@email
            
                    insert into #tmp select * from  @tmpTable       
            
                    DELETE FROM @tmpTable       
                    DELETE FROM @tmpTable2 WHERE emailNumber= @Email
            
                    set @counter =@counter -1
            
            End
            
            select * from #tmp
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-03-19
              • 1970-01-01
              • 1970-01-01
              • 2013-10-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多