如何将SQL列转换为行?

17

我在SQL Server 2005中遇到一个非常简单的问题,需要一个非常快速和简单的解决方案。

我有一个具有x列的表。 我想能够从表中选择一行,然后将列转换为行。

TableA
Column1, Column2, Column3

返回SQL语句

ResultA
Value of Column1
Value of Column2
Value of Column3
@Kevin:我在谷歌上搜索过这个话题,但很多示例对我的情况来说过于复杂了,你能再帮我一下吗?

@Mario:我正在创建的解决方案有10个列,存储值为0到6,我必须计算出有多少列的值大于或等于3。所以我考虑创建一个查询将其转换成行,然后在子查询中使用生成的表来计算Column >= 3的行数。


嗯...这是我从未尝试过的事情。我想到的解决方案都太棘手、太丑陋了,我相信一定有更优雅的方法。我也搜索了一下UNPIVOT,看起来这就是你应该走的路线。我会把它当作一个谜题,在接下来的几天里解决它。 - Mario Marinato
请查看我的博客:http://sql-tricks.blogspot.com/2011/04/sql-server-rows-transpose.html - Dalex
6个回答

6
你应该看一下UNPIVOT子句。
更新1:GateKiller,奇怪的是我今天早上读了一篇关于它(与此无关)的文章,我正在尝试唤起我在哪里再次看到它的记忆,也有一些看起来不错的例子。我相信我会想起来的。
更新2:找到了:http://weblogs.sqlteam.com/jeffs/archive/2008/04/23/unpivot.aspx

1

我以前为一个项目做过这个。我遇到的主要困难之一是向其他人解释我试图做什么。我花了很多时间尝试在SQL中完成这个,但我发现枢轴函数非常不足。我不记得确切的原因是什么,但它对于大多数应用程序来说过于简单,并且在MS SQL 2000中没有完全实现。最终我在.NET中编写了一个枢轴函数。我会在这里发布它,希望它能帮助某个人,某天。

 ''' <summary>
    ''' Pivots a data table from rows to columns
    ''' </summary>
    ''' <param name="dtOriginal">The data table to be transformed</param>
    ''' <param name="strKeyColumn">The name of the column that identifies each row</param>
    ''' <param name="strNameColumn">The name of the column with the values to be transformed from rows to columns</param>
    ''' <param name="strValueColumn">The name of the column with the values to pivot into the new columns</param>
    ''' <returns>The transformed data table</returns>
    ''' <remarks></remarks>
    Public Shared Function PivotTable(ByVal dtOriginal As DataTable, ByVal strKeyColumn As String, ByVal strNameColumn As String, ByVal strValueColumn As String) As DataTable
        Dim dtReturn As DataTable
        Dim drReturn As DataRow
        Dim strLastKey As String = String.Empty
        Dim blnFirstRow As Boolean = True

        ' copy the original data table and remove the name and value columns
        dtReturn = dtOriginal.Clone
        dtReturn.Columns.Remove(strNameColumn)
        dtReturn.Columns.Remove(strValueColumn)

        ' create a new row for the new data table
        drReturn = dtReturn.NewRow

        ' Fill the new data table with data from the original table
        For Each drOriginal As DataRow In dtOriginal.Rows

            ' Determine if a new row needs to be started
            If drOriginal(strKeyColumn).ToString <> strLastKey Then

                ' If this is not the first row, the previous row needs to be added to the new data table
                If Not blnFirstRow Then
                    dtReturn.Rows.Add(drReturn)
                End If

                blnFirstRow = False
                drReturn = dtReturn.NewRow

                ' Add all non-pivot column values to the new row
                For Each dcOriginal As DataColumn In dtOriginal.Columns
                    If dcOriginal.ColumnName <> strNameColumn AndAlso dcOriginal.ColumnName <> strValueColumn Then
                        drReturn(dcOriginal.ColumnName.ToLower) = drOriginal(dcOriginal.ColumnName.ToLower)
                    End If
                Next
                strLastKey = drOriginal(strKeyColumn).ToString
            End If

            ' Add new columns if needed and then assign the pivot values to the proper column
            If Not dtReturn.Columns.Contains(drOriginal(strNameColumn).ToString) Then
                dtReturn.Columns.Add(drOriginal(strNameColumn).ToString, drOriginal(strValueColumn).GetType)
            End If
            drReturn(drOriginal(strNameColumn).ToString) = drOriginal(strValueColumn)
        Next

        ' Add the final row to the new data table
        dtReturn.Rows.Add(drReturn)

        ' Return the transformed data table
        Return dtReturn
    End Function

0
SELECT IDColumn, 
       NumberOfColumnsGreaterThanThree = (CASE WHEN Column1 >= 3 THEN 1 ELSE 0 END) + 
                                         (CASE WHEN Column2 >= 3 THEN 1 ELSE 0 END) + 
                                         (Case WHEN Column3 >= 3 THEN 1 ELSE 0 END) 
FROM TableA;

0

联合 应该是你的好朋友:

SELECT Column1 FROM table WHERE idColumn = 1
UNION ALL
SELECT Column2 FROM table WHERE idColumn = 1
UNION ALL
SELECT Column3 FROM table WHERE idColumn = 1

但是在处理大量结果集时,它也可能成为你的敌人


0

我不确定 SQL Server 的语法,但在 MySQL 中我会这样做

SELECT IDColumn, ( IF( Column1 >= 3, 1, 0 ) + IF( Column2 >= 3, 1, 0 ) + IF( Column3 >= 3, 1, 0 ) + ... [snip ] )
  AS NumberOfColumnsGreaterThanThree
FROM TableA;

编辑:非常(非常)简短的谷歌搜索告诉我,在MySQL中,CASE语句可以完成我使用IF语句所做的事情。您可能会从我找到的谷歌结果中获得帮助。

进一步编辑:我还应该指出,这不是您问题的答案,而是您实际问题的替代解决方案。


0
如果您有一组固定的列,并且知道它们是什么,您可以基本上执行一系列子查询,如下所示:

(SELECT Column1 AS ResultA FROM TableA) as R1

然后将这些子查询连接起来。所有这些都在单个查询中完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接