检查连接表中的不匹配

时间:2010-07-23 04:05:35

标签: sql

我有两个查询,结果应该是互斥的,但事实并非如此。

这个正确查找所有具有匹配名称和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)

这个应该找到所有没有匹配名称和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) OR emails.id IS NULL)

但是,如果后一个查询的电子邮件不匹配,则会返回具有匹配电子邮件的帐户,因此它会从第一个查询返回帐户。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

考虑以下测试用例:

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);

然后按预期工作:

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)

第二个查询的问题是,如果帐户中没有电子邮件,则可以返回NULL行,如帐号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)

为什么这对于没有NULL行的互斥结果集来说不够?:

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)

答案 1 :(得分:0)

如果您的目标要匹配一对(type_name,order_id),那么它应该有效 -

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