2010-06-17 21 views
5

J'ai une base de données de sondage avec une colonne pour chaque question et une ligne pour chaque personne qui répond. Chaque question reçoit une réponse d'une valeur de 1 à 3.En SQL, comment puis-je compter le nombre de valeurs dans une colonne, puis le faire pivoter pour que la colonne devienne la ligne?

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

Maintenant, je dois afficher les résultats sur une seule ligne par question, avec une colonne pour chaque numéro de réponse, et la valeur de chaque colonne étant le nombre des réponses qui ont utilisé cette réponse. Enfin, j'ai besoin de calculer le score total, qui est le nombre de 1 plus deux fois le nombre de 2 plus trois fois le nombre de trois.

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

Existe-t-il un moyen de le faire en SQL basé sur un ensemble? Je sais comment le faire en utilisant des boucles en C# ou des curseurs en SQL, mais j'essaie de le faire fonctionner dans un outil de reporting qui ne supporte pas les curseurs.

+0

Est-ce que vous voulez faire cela dans un SGBDR particulier? –

+0

Les clés d'identification représentent-elles des questions individuelles ou des utilisateurs individuels? – Kenneth

+0

quel outil de reporting –

Répondre

3

Cela vous donnera ce que vous vous demandez:

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 

Gardez à l'esprit que cela va rapidement ballon vous ajouter des questions ou même des réponses potentielles. Vous pourriez être beaucoup mieux si vous avez normalisé un peu et a eu une table Answers avec une ligne pour chaque réponse avec un code de question ou un id, au lieu de les faire passer en tant que colonnes dans une table. Cela commence à ressembler un peu à la conception de la paire entité-valeur, mais je pense que c'est assez différent pour être utile ici.

+0

Cela a du sens, merci! –

+0

Ce code n'a-t-il pas besoin d'une instruction Grouper par? Pour stocker les données - je suis d'accord avec la normalisation suggérée, mais une fois qu'il s'agit d'analyser, vous devez écrire au moins une vue de type feuille de calcul pour la plupart des progiciels statistiques. Je serais ravi d'avoir tort sur la dernière déclaration ... –

+0

@ ran2 - Il n'a pas besoin de GROUP BY car il somme sur toute la table. Une fois qu'il est normalisé, vous pouvez obtenir ces mêmes données en utilisant une requête similaire, mais sans tous les UNIONs. Vous pouvez également utiliser PIVOT. –

1

Vous pouvez également tirer parti des fonctions de pivotement de SQL 2005 pour obtenir ce que vous voulez. De cette façon, vous n'avez pas besoin de coder en dur les questions comme vous le faites dans la tabulation croisée. Notez que j'ai appelé la table source "mytable" et j'ai utilisé des expressions de table communes pour la lisibilité mais vous pouvez également utiliser des sous-requêtes.

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 

Notez que si vous ne voulez pas la ventilation de la requête est plus 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