2010-09-09 59 views
10

Tengo una tabla con esta estructura.Dividir varias columnas en varias filas

UserID | UserName | AnswerToQuestion1 | AnswerToQuestion2 | AnswerToQuestion3 
1  | John  | 1     | 0     | 1 
2  | Mary  | 1     | 1     | 0 

no puedo averiguar lo consulta SQL que usaría para obtener un conjunto de resultados como esto:

UserID | UserName | QuestionName  | Response 
1  | John  | AnswerToQuestion1 | 1 
1  | John  | AnswerToQuestion2 | 0 
1  | John  | AnswerToQuestion3 | 1 
2  | Mary  | AnswerToQuestion1 | 1 
2  | Mary  | AnswerToQuestion2 | 1 
2  | Mary  | AnswerToQuestion3 | 0 

Estoy tratando de dividir las tres columnas en tres filas separadas. es posible?

Respuesta

6
SELECT 
    Y.UserID, 
    Y.UserName, 
    QuestionName = 'AnswerToQuestion' + X.Which, 
    Response = 
     CASE X.Which 
     WHEN '1' THEN AnswerToQuestion1 
     WHEN '2' THEN AnswerToQuestion2 
     WHEN '3' THEN AnswerToQuestion3 
     END 
FROM 
    YourTable Y 
    CROSS JOIN (SELECT '1' UNION ALL SELECT '2' UNION ALL SELECT '3') X (Which) 

Esto funciona igualmente bien a UNPIVOT (a veces mejor) y trabaja en SQL 2000 también.

Aproveché la similitud de las preguntas para crear la columna QuestionName, pero por supuesto esto funcionará con diferentes nombres de preguntas.

Tenga en cuenta que si su lista de preguntas es larga o los nombres de las preguntas son largos, puede experimentar con 2 columnas en la tabla X, una para el número de pregunta y otra para el nombre de la pregunta. O si ya tiene una tabla con la lista de preguntas, CROSS ÚNASE a eso. Si algunas preguntas son NULL, lo más fácil es colocar la consulta anterior en una tabla CTE o derivada y luego agregar WHERE Response IS NOT NULL.

+0

Aparece el mensaje de pregunta de columna no existe con este – hedgedandlevered

+0

No, mi consulta funciona bien. Usted obtiene ese error solo tratando de referirse al alias 'QuestionName' en otra parte de la consulta. Coloque esta consulta en una tabla derivada y selecciónela, luego puede ponerle condiciones. Estás usando SQL Server, ¿verdad? – ErikE

+0

Oh, no, estoy usando SQL de forma regular. No vi la etiqueta sql-server. Gracias, terminé descifrándolo usando la respuesta de 8kb y la tuya. – hedgedandlevered

5

Suponiendo SQL Server 2005 + puede utilizar UNPIVOT

;with YourTable as 
(
SELECT 1 UserID,'John' UserName,1 AnswerToQuestion1,0 AnswerToQuestion2,1 AnswerToQuestion3 
UNION ALL 
SELECT 2, 'Mary', 1, 1, 0 
) 
SELECT UserID, UserName, QuestionName, Response 
FROM YourTable 
UNPIVOT 
    (Response FOR QuestionName IN 
     (AnswerToQuestion1, AnswerToQuestion2,AnswerToQuestion3) 
)AS unpvt; 
+0

Lo siento por la respuesta tardía y gracias por su respuesta. ¿Hay alguna alternativa al uso del operador UNPIVOT? – Sandro

6

Según Itzik Ben-Gan en Inside Microsoft SQL Server 2008: T-SQL Querying, SQL Server pasa por tres pasos cuando unpivoting una tabla:

  1. generar copias
  2. elementos extracto
  3. Eliminar filas con nulos

Paso 1: Generar copias

Se crea una tabla virtual que tiene una copia de cada fila en la tabla de orignal para cada columna que se está desentreglando. Además, una cadena de caracteres del nombre de columna se almacena en una nueva columna (llámala la columna QuestionName). * Nota: Modifiqué el valor en una de sus columnas a NULL para mostrar el proceso completo.

UserID UserName AnswerTo1 AnswerToQ2 AnswerToQ3 QuestionName 
1  John  1   0   1   AnswerToQuestion1 
1  John  1   0   1   AnswerToQuestion2 
1  John  1   0   1   AnswerToQuestion3 
2  Mary  1   NULL  1   AnswerToQuestion1 
2  Mary  1   NULL  1   AnswerToQuestion2 
2  Mary  1   NULL  1   AnswerToQuestion3 

Paso 2: Extraer los elementos

A continuación, se crea otra tabla que crea una nueva fila para cada valor de la columna de origen que corresponde al valor cadena de caracteres en la columna de la QuestionName. El valor se almacena en una nueva columna (llámala la columna Respuesta).

UserID UserName QuestionName  Response 
1  John  AnswerToQuestion1 1 
1  John  AnswerToQuestion2 0 
1  John  AnswerToQuestion3 1 
2  Mary  AnswerToQuestion1 1 
2  Mary  AnswerToQuestion2 NULL 
2  Mary  AnswerToQuestion3 1 

Paso 3: Eliminar filas con nulos

Este paso filtra cualquier filas que se crearon con valores nulos en la columna de la respuesta. En otras palabras, si alguna de las columnas AnswerToQuestion tenía un valor nulo, no se representaría como una fila no activada.

UserID UserName QuestionName  Response 
1  John  AnswerToQuestion1 1 
1  John  AnswerToQuestion2 0 
1  John  AnswerToQuestion3 1 
2  Mary  AnswerToQuestion1 1 
2  Mary  AnswerToQuestion3 1 

Si usted sigue estos pasos, puede

  1. combinación cruzada todas las filas en la tabla uno contra AnswerToQuestion nombre columna para obtener copias fila
  2. rellenar la columna de respuesta basada en el juego la columna de origen y QuestionName
  3. Elimina los NULL para obtener los mismos resultados de sin usar UNPIVOT.

un ejemplo a continuación:

DECLARE @t1 TABLE (UserID INT, UserName VARCHAR(10), AnswerToQuestion1 INT, 
    AnswertoQuestion2 INT, AnswerToQuestion3 INT 
) 

INSERT @t1 SELECT 1, 'John', 1, 0, 1 UNION ALL SELECT 2, 'Mary', 1, NULL, 1 

SELECT 
    UserID, 
    UserName, 
    QuestionName, 
    Response 
FROM (
    SELECT 
    UserID, 
    UserName, 
    QuestionName, 
    CASE QuestionName 
     WHEN 'AnswerToQuestion1' THEN AnswerToQuestion1 
     WHEN 'AnswerToQuestion2' THEN AnswertoQuestion2 
     ELSE AnswerToQuestion3 
    END AS Response 
    FROM @t1 t1 
     CROSS JOIN (
     SELECT 'AnswerToQuestion1' AS QuestionName 
     UNION ALL SELECT 'AnswerToQuestion2' 
     UNION ALL SELECT 'AnswerToQuestion3' 
    ) t2 
    ) t3 
WHERE Response IS NOT NULL 
+0

Muchas gracias por la respuesta de calidad. Me gusta mucho su respuesta, ya que es la más detallada, pero es posible que tenga que darle la respuesta a Emtucifor por responder solo unas horas antes que usted. ¡Gracias! – Sandro