我对如何在SQL中执行此操作感到不满。我有一张桌子:
| User_id | Question_ID | Answer_ID |
| 1 | 1 | 1 |
| 1 | 2 | 10 |
| 2 | 1 | 2 |
| 2 | 2 | 11 |
| 3 | 1 | 1 |
| 3 | 2 | 10 |
| 4 | 1 | 1 |
| 4 | 2 | 10 |
它包含用户对特定问题的答案。一个问题可能有多个答案。用户无法回答两次相同的问题。 (因此,每个{User_id,Question_ID}只有一个Answer_ID)
我正在尝试找到此查询的答案:对于特定问题和答案ID(与同一问题相关),我想找到具有给定答案的用户对OTHER问题给出的最常见答案。< / p>
例如,对于上表:
For question_id = 1 -> For Answer_ID = 1 - (Question 2 - Answer ID 10)
For Answer_ID = 2 - (Question 2 - Answer ID 11)
是否可以在一个查询中执行?它应该在一个查询中完成吗?我应该只使用存储过程或Java吗?
答案 0 :(得分:4)
您的问题似乎有多个步骤。
获取有关“具有给定答案的用户的问题”的信息。设计此SELECT
并假设结果形成一个新表。
应用“OTHER”限制。这可能是AND ... != ...
添加的次要SELECT #1
。
现在找到“最常见的答案”。这可能涉及ORDER BY COUNT(*) DESC LIMIT 1
。很可能
使用派生表:
SELECT ...
FROM ( select#2 )
答案 1 :(得分:4)
虽然@ rick-james是对的,但我不确定如果不是这样的查询通常是为MySQL编写的,那么很容易启动。
您需要查询才能找到问题的最常见答案:
SELECT
question_id,
answer_id,
COUNT(*) as cnt
FROM user_answers
GROUP BY 1, 2
ORDER BY 1, 3 DESC
这将返回一个表格,其中我们输出的每个question_id按降序排列。
| 1 | 1 | 3 |
| 1 | 2 | 1 |
| 2 | 10 | 3 |
| 2 | 11 | 1 |
现在我们应该解决所谓的greatest-n-per-group任务。问题在于,在MySQL中为了性能,这样的任务通常不是在纯SQL中解决,而是使用黑客知识如何在内部处理查询。
在这种情况下,我们知道我们可以定义一个变量,然后遍历ready表,了解前一行,这样我们就可以区分组中的第一行和其他行。
SELECT
question_id, answer_id, cnt,
IF(question_id=@q_id, NULL, @q_id:=question_id) as v
FROM (
SELECT
question_id, answer_id, COUNT(*) as cnt
FROM user_answers
GROUP BY 1, 2
ORDER BY 1, 3 DESC) cnts
JOIN (
SELECT @q_id:=-1
) as init;
确保已初始化变量(并在初始化时尊重其数据类型,否则可能会在以后意外地进行转换)。结果如下:
| 1 | 1 | 3 | 1 |
| 1 | 2 | 1 |(null)|
| 2 | 10 | 3 | 2 |
| 2 | 11 | 1 |(null)|
现在我们只需要在最后一列中过滤掉NULL的行。由于实际上不需要该列,我们可以将相同的表达式移动到WHERE子句中。实际上也不需要cnt列,因此我们也可以跳过它:
SELECT
question_id, answer_id
FROM (
SELECT
question_id, answer_id
FROM user_answers
GROUP BY 1, 2
ORDER BY 1, COUNT(*) DESC) cnts
JOIN (
SELECT @q_id:=-1
) as init
WHERE IF(question_id=@q_id, NULL, @q_id:=question_id) IS NOT NULL;
最后值得一提的是,为了使查询有效,您应该拥有正确的索引。此查询需要以(question_id,answer_id)列开头的索引。由于您无论如何都需要UNIQUE索引,因此按以下顺序定义它是有意义的:(question_id,answer_id,user_id)。
CREATE TABLE user_answers (
user_id INTEGER,
question_id INTEGER,
answer_id INTEGER,
UNIQUE INDEX (question_id, answer_id, user_id)
) engine=InnoDB;
这是一个可以玩的方形小说:http://sqlfiddle.com/#!9/bd12ad/20。
答案 2 :(得分:1)
您的问题是多条件的,您必须向Question
表中的询问用户提出第一个问题:
select question_id,user_id from question
然后插入问题的答案,并在您的Java代码中进行一些检查(用户已经回答了与提出此问题的用户相同的问题,用户多次回答此问题)。
select question_id,user_id from question where user_id=asking-user_id // gets all questions and show on UI
select answer_id,user_id from answer where user_id=answering-user_id // checks the answers that particular user