2013-03-07 2 views
1

J'ai une base de données MySQL avec deux tables pour les questions et réponses. Chaque question a une réponse correcte et trois réponses incorrectes. Il y a toujours quatre réponses pour chaque question et une seule est correcte.SELECT requête obtenant des lignes de table en tant que colonnes dans MySQL

Les tables sont:

CREATE TABLE `question` (
    `id_question` smallint(5) unsigned NOT NULL auto_increment, 
    `text` varchar(255) collate utf8_unicode_ci default NULL, 
    PRIMARY KEY (`id_question`), 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 


CREATE TABLE `answer` (
    `id_answer` mediumint(8) unsigned NOT NULL auto_increment, 
    `id_question` smallint(5) unsigned NOT NULL, 
    `is_correct` tinyint(1) NOT NULL, 
    `text` varchar(45) collate utf8_unicode_ci default NULL, 
    PRIMARY KEY (`id_answer`,`id_question`), 
    KEY `fk_id_question_idx` (`id_question`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

J'ai besoin d'aide avec une requête de sélection. Je voudrais obtenir une table avec des questions dans les rangées et les quatre réponses en colonnes (d'abord la bonne, puis les trois autres). Jusqu'à présent, j'ai été en mesure d'obtenir une sortie comme celle-ci:

Question | Answer | Is_Correct 
------------------------------- 
Question 1 Answer 1-1 1 
Question 1 Answer 1-2 0 
Question 1 Answer 1-3 0 
Question 1 Answer 1-4 0 
Question 2 Answer 2-1 1 
Question 2 Answer 2-2 0 
Question 2 Answer 2-3 0 
Question 2 Answer 2-4 0 
... 

Comment puis-je obtenir le résultat suivant?

Question | Correct_Answer | Incorrect_answer1 | Incorrect_answer2 | Incorrect_answer3 
-------------------------------------------------------------- 
Question 1 Answer 1-1 Answer 1-2 Answer 1-3 Answer 1-4 
Question 2 Answer 2-1 Answer 2-2 Answer 2-3 Answer 2-4 
+0

Je ne suis pas familier avec les requêtes de pivot dans MySQL, mais qui est un bon endroit pour commencer googler :). J'aimerais pouvoir aider plus ... Je suis sûr que quelqu'un affichera la réponse. –

Répondre

2

Vous pouvez pivot les données en utilisant une fonction d'agrégation avec une expression CASE. Vous pouvez utiliser des variables définies par l'utilisateur pour implémenter un numéro de ligne sur chaque ligne par question. Votre code sera semblable à ceci:

select q.text Question, 
    max(case when a.is_correct = 1 then a.text end) Correct_answer, 
    max(case when a.is_correct = 0 and rn=1 then a.text end) Incorrect_Answer1, 
    max(case when a.is_correct = 0 and rn=2 then a.text end) Incorrect_Answer2, 
    max(case when a.is_correct = 0 and rn=3 then a.text end) Incorrect_Answer3 
from question q 
inner join 
(
    select a.id_question, 
    a.text, 
    a.is_correct, 
    a.id_answer, 
    @row:=case 
      when @prevQ=id_question 
       and is_correct = 0 
      then @row +1 
      else 0 end rn, 
    @prevA:=id_answer, 
    @prevQ:=id_question 
    from answer a 
    cross join (select @row:=0, @prevA:=0, @prevQ:=0)r 
    order by a.id_question, a.id_answer 
) a 
    on q.id_question = a.id_question 
group by q.text 
order by a.id_question, a.id_answer 

Voir SQL Fiddle with Demo. Cela donne le résultat dans des colonnes distinctes:

| QUESTION | CORRECT_ANSWER | INCORRECT_ANSWER1 | INCORRECT_ANSWER2 | INCORRECT_ANSWER3 | 
------------------------------------------------------------------------------------------- 
| Question 1 |  Answer 1-1 |  Answer 1-2 |  Answer 1-3 |  Answer 1-4 | 
| Question 2 |  Answer 2-1 |  Answer 2-2 |  Answer 2-3 |  Answer 2-4 | 
1

La construction d'une requête de pivot dynamique pour cela demande beaucoup de travail. Au lieu de cela, ce que je serais probablement faire est d'utiliser GROUP_CONCAT() fonction d'agrégation de MySQL pour créer une liste séparée par des virgules des Incorrect_answer champs, tout en séparant le Correct_Answer comme sa propre colonne:

SELECT 
    question.`text`, 
    /* Separate the one where Is_Correct = 1 and discard the others with a MAX() aggregate */ 
    MAX(CASE WHEN Is_Correct = 1 THEN answer.`text` ELSE NULL END) AS Correct_Answer, 
    /* Group the rows where Is_Correct = 0 into a comma-separated list */ 
    GROUP_CONCAT(CASE WHEN Is_Correct = 0 THEN answer.`text` ELSE NULL END) AS Incorrect_answers 
FROM 
    question 
    JOIN answer ON question.id_question = answer.id_question 
GROUP BY Question.`text` 

Le résultat ce produit tel que reçu par votre code d'application ressemble à:

Question  Correct_Answer Incorrect_answers 
-------------------------------------------------------------- 
Question 1 Answer 1-1 Answer 1-2,Answer 1-3,Answer 1-4 
Question 2 Answer 2-1 Answer 2-2,Answer 2-3,Answer 2-4 

il devient alors trivial dans votre code d'application pour diviser la colonne Incorrect_answers sur le , car il est une liste séparée par des virgules.

En PHP par exemple, quelque chose comme:

$incorrect = explode(',', $row['Incorrect_answers']); 

Ou en Ruby ou Python:

incorrect = incorrect_answers.split(',') 
Questions connexes