2009-07-27 7 views
1

J'ai une table et je souhaite transposer ses lignes en colonnes, similaire à un tableau croisé dynamique mais sans récapituler.Lignes SQL vers colonnes

Par exemple, j'ai les tableaux suivants:

Question 
--QuestionID 
--QuestionText 

Response 
--ResponseID 
--ResponseText 
--QuestionID 

Fondamentalement, je veux être en mesure de créer une table quelque chose dynamique comme:

Question 1 Text | Question 2 Text | Question 3 Text 
--------------------------------------------------- 
Response 1.1 Text | Response Text 1.2 | Response 1.3 
Response 2.1 Text | Response Text 2.2 | Response 2.3 
Response 3.1 Text | Response Text 3.2 | Response 3.3 
Response 4.1 Text | Response Text 4.2 | Response 4.3 

L'exigence principale serait que je ne sais pas au moment du design, quel sera le texte de la question?

S'il vous plaît quelqu'un peut-il aider - je tire mes cheveux: oS

vous pouvez essentiellement garantir qu'il y aura une réponse pour chaque question correspondante dans ce scénario.

+0

Quel serveur de base de données? – AakashM

+1

Ce sera SQL Server. C'est toujours sanglant SQL Server. – skaffman

+0

Oui, SQL Server. Je l'ai fait ce dont j'avais besoin pour utiliser le XML, et atteindre l'agrégation si une fonction – IThasTheAnswer

Répondre

7

Vous ne pouvez pas le faire avec SQL (sauf avec les requêtes dynamiques), sauf si vous connaissez le nombre de colonnes (c'est-à-dire les questions) au moment du design.

Vous devez tirer les données que vous souhaitez en format tableau et traiter ensuite du côté client:

SELECT * 
FROM Question 
LEFT OUTER JOIN 
     Response 
ON  Response.QuestionId = Question.QuestionID 

ou, probablement, ce (en SQL Server 2005+, Oracle 8i+ et PostgreSQL 8.4+):

SELECT * 
FROM (
     SELECT q.*, ROW_NUMBER() OVER (ORDER BY questionID) AS rn 
     FROM Question q 
     ) q 
LEFT OUTER JOIN 
     (
     SELECT r.*, ROW_NUMBER() OVER (PARTITION BY questionID ORDER BY ResponseID) AS rn 
     FROM Response r 
     ) r 
ON  r.QuestionId = q.QuestionID 
     AND q.rn = r.rn 
ORDER BY 
     q.rn, q.QuestionID 

La dernière requête vous donnera des résultats dans ce formulaire (à condition que vous avez 4 questions):

rn  question  response 
---   ---   --- 
1  Question 1 Response 1.1 
1  Question 2 Response 2.1 
1  Question 3 Response 3.1 
1  Question 4 Response 4.1 
2  Question 1 Response 1.2 
2  Question 2 Response 2.2 
2  Question 3 NULL 
2  Question 4 Response 4.2 
3  Question 1 NULL 
3  Question 2 NULL 
3  Question 3 Response 3.3 
3  Question 4 NULL 

, ceci va sortir les données sous forme de tableau, avec rn marquant le numéro de ligne.

Chaque fois que vous voyez le rn changer sur le client, vous fermez simplement <tr> et ouvrez le nouveau.

Vous pouvez en toute sécurité mettre VotreONE l » <td> de par resultset ligne, puisque même nombre ou lignes est garantie à retourner pour chaque rn

Ceci est tout à fait une question souvent posée.

SQL juste pas un bon outil pour renvoyer des données avec le nombre dynamique de colonnes.

SQL fonctionne sur des ensembles, et la disposition des colonnes est une propriété implicite d'un ensemble.

Vous devez définir la disposition de l'ensemble que vous voulez obtenir en temps de conception, tout comme vous définissez le type de données d'une variable dans C.

C fonctionne avec des variables strictement définies, SQL fonctionne avec des ensembles strictement définis.

Notez que je ne dis pas que c'est la meilleure méthode possible. C'est juste la façon dont fonctionne SQL.

Mise à jour:

En SQL Server, vous pouvez tirer la table HTML bonne forme sur la base de données:

WITH a AS 
     (
     SELECT a.*, ROW_NUMBER() OVER (PARTITION BY question_id ORDER BY id) AS rn 
     FROM answer a 
     ), 
     rows AS (
     SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn 
     FROM answer a 
     WHERE question_id = 
       (
       SELECT TOP 1 question_id 
       FROM answer a 
       GROUP BY 
         question_id 
       ORDER BY 
         COUNT(*) DESC 
       ) 
     ) 
SELECT (
     SELECT COALESCE(a.value, '') 
     FROM question q 
     LEFT JOIN 
       a 
     ON  a.rn = rows.rn 
       AND a.question_id = q.id 
     FOR XML PATH ('td'), TYPE 
     ) AS tr 
FROM rows 
FOR XML PATH(''), ROOT('table') 

Voir cette entrée dans mon blog pour plus de détails:

+0

OK, merci pour la réponse. J'espère trouver une solution, ce qui signifie que je me retrouve avec une table pour ensuite effectuer le regroupement et l'agrégation. Je ne peux pas connaître le nombre de colonnes au moment du design, car les colonnes sont basées sur les données utilisateur – IThasTheAnswer

+0

@Tunic: voir après la mise à jour – Quassnoi

+0

Merci. J'ai déjà une solution similaire côté client car j'utilise XSLT pour traiter les données. Le problème est que j'ai finalement besoin de connaître les combinaisons de résultats, donc pourquoi je voulais que les données tabulaires de SQL puissent ensuite se regrouper et agréger – IThasTheAnswer

0

Commencez par grouper et agréger en utilisant la réponse de Quassnoi comme résultat intermédiaire.

Vous ne devez effectuer un calcul croisé que lorsque vous ne souhaitez plus effectuer d'opération orientée jeu sur les résultats. Certains dialectes SQL ont des mots-clés comme PIVOT, TRANSFORM ou CROSSTABULATE pour accomplir ceci, mais vous êtes probablement mieux d'utiliser XSLT.

+0

Le problème est - que se passe-t-il lorsque vous voulez agréger le résultat du tableau croisé? La seule façon que j'ai jusqu'ici est d'utiliser une fonction pour transformer les champs en une corde concaténée - se sent très sale – IThasTheAnswer

Questions connexes