2010-07-23 66 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