2010-09-09 28 views
10

J'ai une table avec cette structure.Diviser plusieurs colonnes en plusieurs lignes

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

Je ne peux pas comprendre ce que la requête SQL j'utiliser pour obtenir un jeu de résultats comme celui-ci:

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 

Je suis en train de diviser les trois colonnes en trois lignes distinctes. Est-ce possible?

Répondre

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) 

Cela fonctionne aussi bien UNPIVOT (parfois mieux) et travaille dans SQL 2000 ainsi.

J'ai profité de la similarité des questions pour créer la colonne QuestionName, mais bien sûr cela fonctionnera avec différents noms de questions.

Notez que si votre liste de questions est longue ou que les noms des questions sont longs, vous pouvez tester 2 colonnes dans la table X, une pour le numéro de question et une pour le nom de la question. Ou si vous avez déjà une table avec la liste des questions, alors CROSS JOIN à cela. Si certaines questions sont NULL, le plus simple est de placer la requête ci-dessus dans une table CTE ou dérivée, puis d'ajouter WHERE Response IS NOT NULL.

+0

Je reçois «colonne nom de question n'existe pas» avec ce – hedgedandlevered

+0

Non, ma requête fonctionne très bien. Vous obtenez cette erreur uniquement en essayant de faire référence à l'alias 'QuestionName' ailleurs dans la requête. Placez cette requête dans une table dérivée et sélectionnez-la, vous pouvez y ajouter des conditions. Vous utilisez SQL Server, n'est-ce pas? – ErikE

+0

Oh, non, j'utilise le SQL normal. N'a pas vu la balise sql-server. Merci, fini par le comprendre en utilisant la réponse de 8kb et la vôtre. – hedgedandlevered

5

En supposant SQL Server 2005+ vous pouvez utiliser 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

Désolé pour la réponse tardive et merci pour votre réponse. Existe-t-il des alternatives à l'utilisation de l'opérateur UNPIVOT? – Sandro

6

Selon Itzik Ben-Gan dans Inside Microsoft SQL Server 2008: T-SQL Querying, SQL Server passe par trois étapes lors de unpivoting une table:

  1. générer des copies
  2. éléments Extrait
  3. Retirer les lignes avec NULLs

Étape 1: Générer des copies

Une table virtuelle est créée avec une copie de chaque ligne de la table orignal pour chaque colonne qui est en cours de non-pivotement. En outre, une chaîne de caractères du nom de colonne est stockée dans une nouvelle colonne (appelez ceci la colonne QuestionName). * Note: J'ai modifié la valeur de l'une de vos colonnes à NULL pour afficher le processus complet.

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 

Etape 2: éléments d'extrait

Puis une autre table est créée qui crée une nouvelle ligne pour chaque valeur de la colonne de la source qui correspond à la valeur de chaîne de caractères dans la colonne QuestionName. La valeur est stockée dans une nouvelle colonne (appelez ceci la colonne Response).

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 

Étape 3: Supprimer les lignes avec NULLS

Cette étape filtre les lignes qui ont été créés avec des valeurs nulles de la colonne de réaction. En d'autres termes, si l'une des colonnes AnswerToQuestion avait une valeur nulle, elle ne serait pas représentée comme une ligne non pivotée.

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 vous suivez ces étapes, vous pouvez

  1. CROSS JOIN toutes les lignes de la table contre chaque AnswerToQuestion nom de colonne pour obtenir des copies de ligne
  2. alimenter la colonne de réponse basée sur la mise en correspondance la colonne source et QuestionName
  3. Supprimez les valeurs NULL pour obtenir les mêmes résultats sans utiliser UNPIVOT.

Un exemple ci-dessous:

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

Merci beaucoup pour la réponse de qualité. J'aime beaucoup votre réponse, car elle est la plus détaillée, mais je pourrais devoir donner la réponse à Emtucifor pour avoir répondu quelques heures avant vous. Je vous remercie! – Sandro

Questions connexes