2010-08-25 8 views
0

Il semble assez simple que j'ai une table 'question' qui stocke une liste de toutes les questions et une table plusieurs à plusieurs qui se trouve entre 'question' et 'utilisateur' appelé 'question_answer'.MySQL Quitter Joindre avec conditionnel

Est-il possible de faire une requête pour récupérer toutes les questions dans la table des questions et celles que l'utilisateur a répondu à l'ONU a répondu aux questions étant des valeurs NULL

question:

| id | question | 

question_answer:

| id | question_id | answer | user_id | 

Je fais cette requête, mais la condition est que seules les questions auxquelles on répond sont renvoyées. Vais-je avoir besoin de sélectionner imbriqué?

SELECT * FROM `question` LEFT JOIN `question_answer` 
ON question_answer.question_id = question.id 
WHERE user_id = 14583461 GROUP BY question_id 

Répondre

0

Vous ne devriez pas utiliser RIGHT JOIN?

SELECT * FROM question_answer RIGHT JOIN question ON question_answer.question_id = question.id 
WHERE user_id = 14583461 GROUP BY question_id 
1

si user_id est dans la partie extérieure jointe à la table alors votre prédicat user_id = 14583461 entraînera ne pas retourner toutes les lignes où user_id est nulle à savoir les lignes avec des questions sans réponse. Vous devez dire "user_id = 14583461 ou user_id est nul"

+0

ouais cela ne fonctionne que si chaque question a une ligne dans la table de questions_answer. – bertsisterwanda

0

quelque chose comme ça pourrait aider (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; 

modifier: a ajouté quelques statistiques/expliquent le plan & exécution:

Durée: 0,031 (10 000 utilisateurs, 1 000 questions, 3,5 millions de réponses)

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 
+0

Une jointure croisée n'est pas requise ici et sera coûteuse même sur des jeux de données modestes. –

+0

je doute que ce soit si cher compte tenu qu'ils spécifient un seul utilisateur. 1 utilisateur * n questions * n ans est un peu trivial. –

+0

Mes excuses, ici c'est effectivement une jointure interne car la condition de jointure inclut un prédicat sur la table de questions. –

0

Déplacez le prédicat user_id dans la condition de jointure. Cela garantira ensuite que toutes les lignes de question sont renvoyées, mais uniquement les lignes question_answer avec l'ID utilisateur et l'ID de question spécifiés.

SELECT * FROM question 
    LEFT JOIN question_answer ON question_answer.question_id = question.id 
           AND user_id = 14583461 
ORDER BY user_id, question_id 
+0

Je suis sry mais je ne peux pas croire que vous avez accpété cette réponse http://paste.pocoo.org/show/254375/ –

+0

Je suis supprimé le «GROUP BY» car il est inutile (il était seulement là comme c'était dans la requête originale). Et ajouté une commande par clause. Pour obtenir des questions pour plus d'un utilisateur, vous pouvez simplement modifier la condition de jointure pour utiliser 'user_id IN (...)'. –

+0

@ar - il ne fonctionne toujours pas correctement, s'il vous plaît jeter un oeil à ce qui suit: http://i37.tinypic.com/24y8w2s.jpg –