2010-06-17 17 views
5

Tengo una base de datos de encuestas con una columna por cada pregunta y una fila por cada persona que responde. Cada pregunta se responde con un valor de 1 a 3.En SQL, ¿cómo puedo contar el número de valores en una columna y luego pivotar para que la columna se convierta en la fila?

Id Quality? Speed? 
-- ------- ----- 
1  3   1 
2  2   1 
3  2   3 
4  3   2 

Ahora, necesito mostrar los resultados como una fila por cada pregunta, con una columna para cada número de respuesta, y el valor de cada columna es el número de respuestas que usaron esa respuesta. Finalmente, necesito calcular el puntaje total, que es el número de 1 más dos veces el número de 2 más tres veces el número de tres.

Question 1 2 3 Total 
-------- -- -- -- ----- 
Quality? 0 2 2 10 
Speed? 2 1 1 7 

¿Hay alguna manera de hacerlo en SQL basado en conjuntos? Sé cómo hacerlo utilizando bucles en C# o cursores en SQL, pero estoy tratando de hacerlo funcionar en una herramienta de informes que no admita los cursores.

+0

¿Quieres hacer esto en cualquier RDBMS en particular? –

+0

¿Las teclas de identificación representan preguntas individuales o usuarios individuales? – Kenneth

+0

qué herramienta de informes –

Respuesta

3

Esto le dará lo que está pidiendo:

SELECT 
    'quality' AS question, 
    SUM(CASE WHEN quality = 1 THEN 1 ELSE 0 END) AS [1], 
    SUM(CASE WHEN quality = 2 THEN 1 ELSE 0 END) AS [2], 
    SUM(CASE WHEN quality = 3 THEN 1 ELSE 0 END) AS [3], 
    SUM(quality) 
FROM 
    dbo.Answers 
UNION ALL 
SELECT 
    'speed' AS question, 
    SUM(CASE WHEN speed = 1 THEN 1 ELSE 0 END) AS [1], 
    SUM(CASE WHEN speed = 2 THEN 1 ELSE 0 END) AS [2], 
    SUM(CASE WHEN speed = 3 THEN 1 ELSE 0 END) AS [3], 
    SUM(speed) 
FROM 
    dbo.Answers 

Tenga en cuenta sin embargo que esto se inflará rápidamente a medida que añada preguntas o incluso respuestas posibles. Es posible que esté mucho mejor si se normalizó un poco y tenía una tabla de Respuestas con una fila para cada respuesta con un código o ID de pregunta, en lugar de ponerlos como columnas en una tabla. Comienza a parecerse un poco al diseño de pares entidad-valor, pero creo que es lo suficientemente diferente como para ser útil aquí.

+0

¡Eso tiene sentido, gracias! –

+0

¿No necesita este código una declaración Agrupar por? Para almacenar los datos, estoy de acuerdo con la normalización sugerida, pero una vez que se trata de analizar, debe escribir al menos una vista de tipo de hoja de cálculo para la mayoría de los paquetes de software estadístico. Me encantaría que se demuestre que estoy equivocado en el último enunciado ... –

+0

@ ran2 - No necesita un GROUP BY porque se está sumando en toda la tabla. Una vez que esté normalizado, puede obtener estos mismos datos usando una consulta similar, pero sin todos los UNION. También puedes usar PIVOT. –

1

También puede aprovechar las funciones pivotantes de SQL 2005 para lograr lo que desea. De esta forma, no necesita codificar todas las preguntas como lo hace en la tabulación cruzada. Tenga en cuenta que llamé a la tabla de origen "mytable" y utilicé expresiones de tabla comunes para la legibilidad, pero también podría usar subconsultas.

WITH unpivoted AS (
    SELECT id, value, question 
    FROM mytable a 
    UNPIVOT (value FOR question IN (quality,speed)) p 
) 
,counts AS (
    SELECT question, value, count(*) AS counts 
    FROM unpivoted 
    GROUP BY question, value 
) 
, repivoted AS (
    SELECT question, counts, [1], [2], [3] 
    FROM counts 
    PIVOT (count(value) FOR value IN ([1],[2],[3])) p 
) 
SELECT question, sum(counts*[1]) AS [1], sum(counts*[2]) AS [2], sum(counts*[3]) AS [3] 
    ,sum(counts*[1]) + 2*sum(counts*[2]) + 3*sum(counts*[3]) AS Total 
FROM repivoted 
GROUP BY question 

Nota Si no desea que la ruptura de la consulta es más simple:

WITH unpivoted AS (
    SELECT id, value, question 
    FROM mytable a 
    UNPIVOT (value FOR question IN (quality,speed)) p 
) 
, totals AS (
    SELECT question, value, count(value)*value AS score 
    FROM unpivoted 
    GROUP BY question, value 
) 
SELECT question, sum(score) AS score 
FROM totals 
GROUP BY question 
Cuestiones relacionadas