Pregunta

Tengo un problema muy simple que requiere una solución muy rápida y sencilla en SQL Server 2005.

Tengo una tabla con x columnas.Quiero poder seleccionar una fila de la tabla y luego transformar las columnas en filas.

TableA
Column1, Column2, Column3

Declaración SQL para ruturn

ResultA
Value of Column1
Value of Column2
Value of Column3

@Kevin: Hice una búsqueda en Google sobre el tema, pero muchos de los ejemplos eran demasiado complejos para mi ejemplo. ¿Puedes ayudar más?

@Mario:La solución que estoy creando tiene 10 columnas que almacenan los valores del 0 al 6 y debo calcular cuántas columnas tienen el valor 3 o más.Así que pensé en crear una consulta para convertirla en filas y luego usar la tabla generada en una subconsulta para decir contar el número de filas con Columna >= 3.

¿Fue útil?

Solución

Deberías echarle un vistazo a la cláusula UNPIVOT.

Actualización1:GateKiller, por extraño que parezca, leí un artículo (sobre algo no relacionado) al respecto esta mañana y estoy tratando de recordar dónde lo vi nuevamente, también tenía algunos ejemplos que parecían decentes.Volverá a mí, estoy seguro.

Actualización2:Lo encontré: http://weblogs.sqlteam.com/jeffs/archive/2008/04/23/unpivot.aspx

Otros consejos

Tuve que hacer esto para un proyecto antes.Una de las mayores dificultades que tuve fue explicar lo que estaba tratando de hacer a otras personas.Pasé mucho tiempo intentando hacer esto en SQL, pero encontré que la función de pivote era lamentablemente inadecuada.No recuerdo la razón exacta por la que fue así, pero es demasiado simplista para la mayoría de las aplicaciones y no está completamente implementado en MS SQL 2000.Terminé escribiendo una función pivote en .NET.Lo publicaré aquí con la esperanza de que algún día ayude a alguien.

 ''' <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

UNIÓN debería ser tu amigo:

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

pero puede también sé tu enemigo en grandes conjuntos de resultados.

Si tiene un conjunto fijo de columnas y sabe cuáles son, básicamente puede hacer una serie de subselecciones.

(SELECT Column1 AS ResultA FROM TableA) as R1

y únete a las subselecciones.Todo esto en una sola consulta.

No estoy seguro de la sintaxis de SQL Server para esto, pero en MySQL lo haría

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

EDITAR:Una búsqueda muy (muy) breve en Google me dice que el CASE declaración hace lo que estoy haciendo con el IF declaración en MySQL.Puede que le aproveches o no el resultado de Google que encontré

EDICIÓN ADICIONAL:También debo señalar que esta no es una respuesta a su pregunta sino una solución alternativa a su problema real.

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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top