Кажется довольно простым, у меня есть "вопрос в таблице", в котором хранится список всех вопросов и множество таблиц, которые находятся между "вопросом" и "пользователем" под названием "question_answer".
Можно ли сделать один запрос, чтобы вернуть все вопросы в таблицу вопросов и те ответы, на которые пользователь ответил без ответа на вопросы, имеющие значения NULL.
Вопрос:
| id | question |
question_answer:
| id | question_id | answer | user_id |
Я делаю этот запрос, но это условие гарантирует, что возвращаются только ответы на вопросы. Нужно ли мне прибегать к вложенному выбору?
SELECT * FROM `question` LEFT JOIN `question_answer`
ON question_answer.question_id = question.id
WHERE user_id = 14583461 GROUP BY question_id
если user_id находится во внешнем соединенном с таблицей, тогда ваш предикат user_id = 14583461 приведет к тому, что не будут возвращены строки, где user_id имеет значение null, то есть строки с неотвеченными вопросами. Вы должны сказать: "user_id = 14583461 или user_id null"
Переместите предикат user_id в условие соединения. Это гарантирует, что будут возвращены все строки из question
, но только строки из question_answer
с указанным идентификатором пользователя и идентификатором вопроса.
SELECT * FROM question
LEFT JOIN question_answer ON question_answer.question_id = question.id
AND user_id = 14583461
ORDER BY user_id, question_id
GROUP BY
как он не нужен (он был только там, как это было в исходном запросе). И добавил порядок по пункту. Чтобы получить вопросы для более чем одного пользователя, вы можете просто изменить условие объединения, чтобы использовать user_id IN (...)
.
что-то вроде этого может помочь (http://pastie.org/1114844)
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) not null
)engine=innodb;
drop table if exists question;
create table question
(
question_id int unsigned not null auto_increment primary key,
ques varchar(255) not null
)engine=innodb;
drop table if exists question_ans;
create table question_ans
(
user_id int unsigned not null,
question_id int unsigned not null,
ans varchar(255) not null,
primary key (user_id, question_id)
)engine=innodb;
insert into users (username) values
('user1'),('user2'),('user3'),('user4');
insert into question (ques) values
('question1 ?'),('question2 ?'),('question3 ?');
insert into question_ans (user_id,question_id,ans) values
(1,1,'foo'), (1,2,'mysql'), (1,3,'php'),
(2,1,'bar'), (2,2,'oracle'),
(3,1,'foobar');
select
u.*,
q.*,
a.ans
from users u
cross join question q
left outer join question_ans a on a.user_id = u.user_id and a.question_id = q.question_id
order by
u.user_id,
q.question_id;
select
u.*,
q.*,
a.ans
from users u
cross join question q
left outer join question_ans a on a.user_id = u.user_id and a.question_id = q.question_id
where
u.user_id = 2
order by
q.question_id;
edit: добавлена статистика/пояснения и время выполнения:
время выполнения: 0,031 (10 000 пользователей, 1000 вопросов, 3,5 миллиона ответов)
select count(*) from users
count(*)
========
10000
select count(*) from question
count(*)
========
1000
select count(*) from question_ans
count(*)
========
3682482
explain
select
u.*,
q.*,
a.ans
from users u
cross join question q
left outer join question_ans a on a.user_id = u.user_id and a.question_id = q.question_id
where
u.user_id = 256
order by
u.user_id,
q.question_id;
id select_type table type possible_keys key key_len ref rows Extra
== =========== ===== ==== ============= === ======= === ==== =====
1 SIMPLE u const PRIMARY PRIMARY 4 const 1 Using filesort
1 SIMPLE q ALL 687
1 SIMPLE a eq_ref PRIMARY PRIMARY 8 const,foo_db.q.question_id 1
Не следует использовать ПРАВИЛЬНОЕ СОЕДИНЕНИЕ?
SELECT * FROM question_answer RIGHT JOIN question ON question_answer.question_id = question.id
WHERE user_id = 14583461 GROUP BY question_id