I have a MySQL database with two tables for questions and answers. Each question has a correct answer and three incorrect answers. There are always four answers for every question and only one is correct.
我有一个MySQL数据库,有两个表用于回答问题。每个问题都有一个正确的答案和三个错误的答案。每个问题总有四个答案,只有一个是正确的。
The tables are:
表:
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;
I need help with a select query. I would like to get a table with questions in the rows and the four answers as columns (first the correct one and then the other three). So far I was able to get an output like this:
我需要一个select查询的帮助。我想要一个列有问题的表格,四个答案作为列(首先是正确的,然后是另外三个)。到目前为止,我能够得到这样的输出:
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
...
How I can get the following result?
如何得到以下结果?
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
2 个解决方案
#1
2
You can pivot the data by using an aggregate function with a CASE
expression. You can use user-defined variables to implement a row number on each row by question. Your code will be similar to this:
您可以使用带有CASE表达式的聚合函数来透视数据。您可以使用用户定义的变量对每一行按问题实现行号。您的代码将类似于:
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
See SQL Fiddle with Demo. This gives the result in separate columns:
参见SQL小提琴演示。这就得到了单独列的结果:
| 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 |
#2
1
Constructing a dynamic pivot query for this is a lot of work. Instead, what I would probably do is use MySQL's GROUP_CONCAT()
aggregate function to create a comma-separated list of the Incorrect_answer
fields, while separating out the Correct_Answer
as its own column:
为此构造一个动态的pivot查询需要大量的工作。相反,我可能要做的是使用MySQL的GROUP_CONCAT()聚合函数创建Incorrect_answer字段的逗号分隔列表,同时将Correct_Answer作为自己的列:
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`
The result this produces as received by your application code looks like:
您的应用程序代码接收到的结果如下:
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
It then becomes trivial in your application code to split the Incorrect_answers
column on the ,
since it is a comma-separated list.
然后,分割Incorrect_answers列在应用程序代码中就变得很简单了,因为它是一个逗号分隔的列表。
In PHP for example, something like :
在PHP中,比如:
$incorrect = explode(',', $row['Incorrect_answers']);
Or in Ruby or Python:
或者用Ruby或Python:
incorrect = incorrect_answers.split(',')
#1
2
You can pivot the data by using an aggregate function with a CASE
expression. You can use user-defined variables to implement a row number on each row by question. Your code will be similar to this:
您可以使用带有CASE表达式的聚合函数来透视数据。您可以使用用户定义的变量对每一行按问题实现行号。您的代码将类似于:
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
See SQL Fiddle with Demo. This gives the result in separate columns:
参见SQL小提琴演示。这就得到了单独列的结果:
| 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 |
#2
1
Constructing a dynamic pivot query for this is a lot of work. Instead, what I would probably do is use MySQL's GROUP_CONCAT()
aggregate function to create a comma-separated list of the Incorrect_answer
fields, while separating out the Correct_Answer
as its own column:
为此构造一个动态的pivot查询需要大量的工作。相反,我可能要做的是使用MySQL的GROUP_CONCAT()聚合函数创建Incorrect_answer字段的逗号分隔列表,同时将Correct_Answer作为自己的列:
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`
The result this produces as received by your application code looks like:
您的应用程序代码接收到的结果如下:
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
It then becomes trivial in your application code to split the Incorrect_answers
column on the ,
since it is a comma-separated list.
然后,分割Incorrect_answers列在应用程序代码中就变得很简单了,因为它是一个逗号分隔的列表。
In PHP for example, something like :
在PHP中,比如:
$incorrect = explode(',', $row['Incorrect_answers']);
Or in Ruby or Python:
或者用Ruby或Python:
incorrect = incorrect_answers.split(',')