题
我有一个非常简单的问题,需要在 SQL Server 2005 中找到一个非常快速且简单的解决方案。
我有一个包含 x 列的表。我希望能够从表中选择一行,然后将列转换为行。
TableA
Column1, Column2, Column3
返回的 SQL 语句
ResultA
Value of Column1
Value of Column2
Value of Column3
@凯文: 我已经对这个主题进行了谷歌搜索,但很多例子对于我的例子来说过于复杂, 你能提供进一步的帮助吗?
@马里奥:我创建的解决方案有 10 列,存储值 0 到 6,我必须计算出有多少列具有值 3 或更多。所以我考虑创建一个查询将其转换为行,然后在子查询中使用生成的表来计算 Column >= 3 的行数
解决方案
您应该查看 UNPIVOT 子句。
更新1: :GateKiller,奇怪的是,我今天早上读了一篇关于它的文章(关于一些不相关的内容),我试图唤起我的记忆,我再次看到它,也有一些看起来不错的例子。我确信它会回到我身边。
更新2: :找到了: http://weblogs.sqlteam.com/jeffs/archive/2008/04/23/unpivot.aspx
其他提示
我之前必须为一个项目这样做。我遇到的主要困难之一是向其他人解释我想做什么。我花了很多时间试图在 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
如果您有一组固定的列并且知道它们是什么,则基本上可以执行一系列子选择
(SELECT Column1 AS ResultA FROM TableA) as R1
并加入子选择。所有这些都在一个查询中。
我不确定 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;
编辑:一个非常(非常)简短的谷歌搜索告诉我 CASE
声明做了我正在做的事情 IF
MySQL 中的语句。您可能会也可能不会使用 我找到的 Google 结果
进一步编辑:我还应该指出,这不是您问题的答案,而是您实际问题的替代解决方案。
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;