2010-07-23 5 views
1

J'ai deux requêtes dont les résultats doivent être mutuellement exclusifs, mais ils ne le sont pas.Recherche de non-correspondance dans la table de jointure

Celui-ci trouve correctement tous les comptes qui ont un e-mail avec un nom correspondant et order_id:

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE (emails.type_name = 'name' AND emails.order_id = 1) 

Celui-ci devrait devrait trouver tous les comptes qui ne disposent pas d'un e-mail avec un nom correspondant et order_id, ou ne pas un courriel à tous:

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE (!(emails.type_name = 'name' AND emails.order_id = 1) OR emails.id IS NULL) 

Cependant, cette dernière requête comptes retour qui ont un e-mail correspondant si elles ont aussi un e-mail non correspondant, donc il est des comptes retour de la première requête. Toute aide serait grandement appréciée.

Répondre

1

Prenons le cas de test suivant:

CREATE TABLE accounts (id int); 
CREATE TABLE emails (id int, account_id int, type_name varchar(10), order_id int); 

INSERT INTO accounts VALUES (1), (2), (3), (4); 

INSERT INTO emails VALUES (1, 1, 'name', 1); 
INSERT INTO emails VALUES (2, 1, 'no-name', 1); 
INSERT INTO emails VALUES (3, 2, 'name', 1); 
INSERT INTO emails VALUES (4, 2, 'no-name', 1); 
INSERT INTO emails VALUES (5, 3, 'name', 2); 

Ensuite, cela fonctionne comme prévu:

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE (emails.type_name = 'name' AND emails.order_id = 1); 

+------+------+------------+-----------+----------+ 
| id | id | account_id | type_name | order_id | 
+------+------+------------+-----------+----------+ 
| 1 | 1 |   1 | name  |  1 | 
| 2 | 3 |   2 | name  |  1 | 
+------+------+------------+-----------+----------+ 
2 rows in set (0.00 sec) 

Le problème avec votre deuxième requête est qu'il peut renvoyer une NULL ligne s'il y a un compte pas de courriel, comme c'est le cas du numéro de compte 4:

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE (!(emails.type_name = 'name' AND emails.order_id = 1) OR emails.id IS NULL); 

+------+------+------------+-----------+----------+ 
| id | id | account_id | type_name | order_id | 
+------+------+------------+-----------+----------+ 
| 1 | 2 |   1 | no-name |  1 | 
| 2 | 4 |   2 | no-name |  1 | 
| 3 | 5 |   3 | name  |  2 | 
| 4 | NULL |  NULL | NULL  |  NULL | 
+------+------+------------+-----------+----------+ 
4 rows in set (0.01 sec) 

Pourquoi pas ce suffisant pour un résultat mutuellement exclusif fixé sans NULL lignes ?:

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE NOT (emails.type_name = 'name' AND emails.order_id = 1) 

+------+------+------------+-----------+----------+ 
| id | id | account_id | type_name | order_id | 
+------+------+------------+-----------+----------+ 
| 1 | 2 |   1 | no-name |  1 | 
| 2 | 4 |   2 | no-name |  1 | 
| 3 | 5 |   3 | name  |  2 | 
+------+------+------------+-----------+----------+ 
3 rows in set (0.00 sec) 
+0

Merci pour la réponse détaillée! Pour la deuxième requête, je recherche des comptes qui n'ont pas un certain type d'enregistrement de courrier électronique (type_name = 'name' AND order_id = 1). Dans votre exemple, les comptes 1 et 2 ont ce type d'enregistrement de courrier électronique, donc je ne veux pas que ceux-ci soient renvoyés. Compte 3 a un enregistrement d'email qui ne correspond pas, donc je veux que cela renvoyé. Le compte 4 n'a aucun enregistrement de courrier électronique, donc je veux que ce soit retourné parce qu'il ne peut pas correspondre. En résumé: Ma requête renvoie actuellement les comptes 1, 2, 3 et 4. Je ne veux que renvoyer 3 et 4. – tassock

0

Si votre cible est de faire correspondre une paire de (nom_type, order_id), alors il devrait fonctionner -

SELECT * FROM `accounts` 
LEFT OUTER JOIN `emails` ON emails.account_id = accounts.id 
WHERE (emails.type_name != 'name' OR emails.order_id != 1) 
+0

Merci pour votre réponse. Comme pour ma deuxième requête d'origine, elle renvoie les comptes qui ont un enregistrement d'e-mail correspondant s'ils ont également un enregistrement d'e-mail ne correspondant pas. Pour cette deuxième requête, je ne veux pas de comptes s'ils ont un enregistrement de courrier électronique correspondant. – tassock

Questions connexes