2009-01-09 7 views
2

J'ai une requête qui extrait les questions d'une table et les réponses d'une autre.Comment rendre cette requête plus facile à écrire

SELECT 
    questions.question, 
    questions.answers, 
    (SELECT COUNT(answer) FROM answers WHERE question_id = 1 AND answer = 1 
      GROUP BY answer) as ans1, 
    (SELECT COUNT(answer) FROM answers WHERE question_id = 1 AND answer = 2 
      GROUP BY answer) as ans2 
FROM questions 
WHERE questions.id = 1 

Bien que cela fonctionne, je n'aime pas l'idée d'ajouter un sous-requête supplémentaire pour chaque réponse (questions.answers est une chaîne par des virgules seperated réponses possibles). C'est faisable mais je suis sûr qu'il doit y avoir un meilleur moyen. L'essentiel est que différentes questions ont des nombres de réponses différents.

Y a-t-il une meilleure façon de faire ou est-ce une façon acceptable de faire les choses? J'imagine que plusieurs sous-sélections dans une requête pourraient avoir un (petit) succès de performance dans le futur (pas que je sois encore un test de performance).

Si c'est applicable, je ne m'attends pas à avoir plus de 5 réponses par question.

Répondre

8
SELECT q.question, q.answers, 
    SUM(a.answer = 1) AS ans1, 
    SUM(a.answer = 2) AS ans2 
FROM questions q 
LEFT OUTER JOIN answers a ON (q.id = a.question_id) 
WHERE q.id = 1 
GROUP BY q.id; 
+0

C'est beaucoup plus propre - je suppose que je suis obligé d'ajouter une sorte de somme ou sous-sélection pour chaque réponse à la question alors? – Ross

+0

Si vous les voulez dans des colonnes séparées, oui. J'ai écrit le SQL ci-dessus en supposant que vous vouliez que la requête retourne le même résultat que la requête dans votre question initiale. –

+0

D'où vient le tableau des réponses? cela n'apparaît pas dans la question originale. Aussi, vous semblez faire une somme sur la valeur totale de la réponse, ce qui donnerait au nombre d'apparences multiplié par la valeur de la réponse. Vous pouvez utiliser une instruction CASE pour contrôler cela (voir ma réponse) –

2

Cela me semble plutôt bien. Vous pouvez omettre les clauses "group by" sur les sous-requêtes puisque vous ne sélectionnez qu'une valeur de "answer".

Je suppose qu'il y a peut-être quelque chose qui cloche dans votre schéma si vous enregistrez une liste de réponses possibles avec chaque réponse. Cela devrait probablement être dans un tableau séparé avec chaque réponse représentée par une seule ligne. Les chaînes séparées par des délimiteurs sont une grande odeur de code dans la conception de base de données, tout comme les doublons de données que vous attendez à être les mêmes.

+0

Je pensais juste qu'il serait trop compliqué d'ajouter une nouvelle table juste pour les réponses possibles simplement parce qu'elles auront au maximum un ou deux mots. Je le considère cependant car je n'ai pas à être restrictif quant à la ponctuation que j'utilise dans ce cas ;-) Merci pour la note GROUP BY. – Ross

+0

Vous allez vous faire une faveur énorme en normalisant la colonne de réponse. J'ai déjà travaillé sur un système qui était exactement comme le vôtre (les réponses enregistrées aux questions de cette façon). C'était l'enfer. – rmeador

0

N'utilisez-vous pas?

SELECT 
    questions.question, 
    questions.answers, 
    COUNT(answer) 

FROM questions inner join answers 
on questions.id = answer.question_id 
WHERE questions.id = 1 
GROUP BY 
questions.question, 
questions.answers 

Vous obtiendriez des lignes au lieu de colonnes, mais des résultats similaires.

+0

Cela me donne seulement le total des réponses et une rangée. Si vous pensiez une rangée pour chaque réponse qui ne m'aiderait pas si je recevais plusieurs questions désolé :) – Ross

1

peut-être?

SELECT 
    questions.question, 
    questions.answers, 
    (case when answers.answer = 1 then COUNT(answer) end) as ans1, 
    (case when answers.answer = 2 then COUNT(answer) end) as ans2 
    FROM questions left join answers on answers.question_id = questions.id 
    WHERE questionss.id = 1 
    group by questions.id 
0

La méthode standard pour relier plusieurs lignes dans une table pour une ou plusieurs rangées dans une autre table consiste à utiliser une table de liens. Une telle table stockerait dans chacune de ses rangées un identifiant d'une table et l'identifiant de l'autre table associé au premier.

Pour vos questions et réponses, stockant les réponses possibles à une question dans une table de lien (que je pourrais appeler question_answered) pourrait ressemble à ceci:

question_id | answer_id

1 1

1 2

2 3

4 4

4 5

4 6 `

Comme vous pouvez le voir, la question 1 a deux réponses possibles, la question 2 a 1 réponse possible, la question 3 est restée sans réponse en question 4 a reçu 3 réponses différentes.

Bien que je ne suis pas sûr de ce que « réponse = 1 » ou « réponse = 2 » signifie dans votre contexte, en utilisant une table de lien comptant toutes les réponses à une question est facile:

SELECT question, count(answer_id) FROM questions AS q INNER JOIN question_answered AS qa ON qa.question_id = q.id) GROUP BY q.id

0
 SELECT questions.question, 
         questions.answers, 
         A.answer, 
         COUNT(A.answer) 
     FROM  questions Q 
LEFT JOIN  answers A 
      ON  Q.id = A.question_id 
    WHERE  questions.id = 1 
      AND  A.answer IN (1,2) 
GROUP BY  A.answer 
Questions connexes