2010-07-23 40 views
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) 

这一次应该会发现,没有一封带有匹配的名称和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) 

然而,后者的查询返回拥有匹配的电子邮件,如果他们也有不匹配的电子邮件帐户,因此它是第一个查询返回账户。任何帮助将不胜感激。

回答

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

感谢详细的回复!对于第二个查询,我正在查找没有特定类型电子邮件记录的帐户(type_name ='name'AND order_id = 1)。在你的例子中,帐户1和2有这种电子邮件记录,所以我不希望那些返回。帐户3的电子邮件记录不匹配,所以我希望返回。帐户4没有电子邮件记录,所以我希望返回,因为它不匹配。 总结:我的查询目前返回帐户1,2,3和4.我只希望它返回3和4. – tassock 2010-07-23 18:06:52

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

感谢您的回复。就像我的第二个原始查询一样,如果他们也有不匹配的电子邮件记录,则会返回具有匹配的电子邮件记录的帐户。对于第二个查询,如果他们有匹配的电子邮件记录,我不需要帐户。 – tassock 2010-07-23 18:57:06