2010-06-17 16 views
5

Ho un database di sondaggi con una colonna per ogni domanda e una riga per ogni persona che risponde. Ogni domanda si risponde con un valore da 1 a 3.In SQL, come posso contare il numero di valori in una colonna e quindi ruotarlo in modo che la colonna diventi la riga?

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

Ora, devo visualizzare i risultati come una riga per domanda, con una colonna per ogni numero di risposta, e il valore di ogni colonna è il numero di risposte che hanno usato quella risposta. Infine, ho bisogno di calcolare il punteggio totale, che è il numero di 1 più due volte il numero di 2 più tre volte il numero di tre.

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

C'è un modo per farlo in SQL set-based? So come farlo usando loop in C# o cursori in SQL, ma sto cercando di farlo funzionare in uno strumento di reporting che non supporta i cursori.

+0

Vuoi fare questo in una particolare RDBMS? –

+0

Le chiavi id rappresentano singole domande o singoli utenti? – Kenneth

+0

quale strumento di reporting –

risposta

3

Questo vi darà quello che stai chiedendo:

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 

Occorre tuttavia tenere presente che questo pallone velocemente si aggiungono domande o anche potenziali risposte. Potresti stare molto meglio se normalizzi un po 'e avessi una tabella Answers con una riga per ogni risposta con un codice di domanda o un id, invece di inserirli come colonne in una tabella. Inizia ad assomigliare un po 'al design delle coppie di entità-valore, ma penso che sia abbastanza diverso da essere utile qui.

+0

Questo ha senso, grazie! –

+0

Questo codice non richiede un raggruppamento per istruzione? Per la memorizzazione dei dati - sono d'accordo con la normalizzazione suggerita, ma una volta che si tratta di analizzare è necessario scrivere almeno una vista di tipo spreadsheet per la maggior parte dei pacchetti software statistici. Mi piacerebbe essere smentito nell'ultima affermazione ... –

+0

@ ran2 - Non ha bisogno di un GROUP BY perché riassume l'intera tabella. Una volta normalizzato, è possibile ottenere gli stessi dati utilizzando una query simile, ma senza tutti gli UNION. Puoi anche usare PIVOT. –

1

È inoltre possibile sfruttare le funzioni di rotazione di SQL 2005 per ottenere ciò che si desidera. In questo modo non hai bisogno di codificare a fondo le domande come fai nella tabella di tabulazione incrociata. Si noti che ho chiamato la tabella di origine "mytable" e ho utilizzato le espressioni di tabella comuni per la leggibilità, ma è anche possibile utilizzare le sottoquery.

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 se non si desidera che la ripartizione della query è più semplice:

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