ON 子句與 WHERE 子句的不一樣一種更好地理解帶有 WHERE ... IS NULL 子句的複雜匹配條件的簡單方法
Matching-Conditions 與 Where-conditions 的不一樣mysql
關於 「A LEFT JOIN B ON 條件表達式」 的一點提醒sql
ON 條件(「A LEFT JOIN B ON 條件表達式」中的ON)用來決定如何從 B 表中檢索數據行。測試
若是 B 表中沒有任何一行數據匹配 ON 的條件,將會額外生成一行全部列爲 NULL 的數據code
在匹配階段 WHERE 子句的條件都不會被使用。僅在匹配階段完成之後,WHERE 子句條件纔會被使用。它將從匹配階段產生的數據中檢索過濾。rem
讓咱們看一個 LFET JOIN 示例:get
01 |
mysql> CREATE TABLE `product` ( |
02 |
`id` int(10) unsigned NOT NULL auto_increment,
|
03 |
`amount` int(10) unsigned default NULL,
|
05 |
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 |
07 |
mysql> CREATE TABLE `product_details` ( |
08 |
`id` int(10) unsigned NOT NULL,
|
09 |
`weight` int(10) unsigned default NULL,
|
10 |
`exist` int(10) unsigned default NULL,
|
12 |
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
14 |
mysql> INSERT INTO product (id,amount) |
15 |
VALUES (1,100),(2,200),(3,300),(4,400);
|
16 |
Query OK, 4 rows affected (0.00 sec) |
17 |
Records: 4 Duplicates: 0 Warnings: 0 |
19 |
mysql> INSERT INTO product_details (id,weight,exist) |
20 |
VALUES (2,22,0),(4,44,1),(5,55,0),(6,66,1);
|
21 |
Query OK, 4 rows affected (0.00 sec) |
22 |
Records: 4 Duplicates: 0 Warnings: 0 |
24 |
mysql> SELECT * FROM product; |
33 |
4 rows in set (0.00 sec) |
35 |
mysql> SELECT * FROM product_details; |
36 |
+----+--------+-------+ |
37 |
| id | weight | exist | |
38 |
+----+--------+-------+ |
43 |
+----+--------+-------+ |
44 |
4 rows in set (0.00 sec) |
46 |
mysql> SELECT * FROM product LEFT JOIN product_details |
47 |
ON (product.id = product_details.id);
|
48 |
+----+--------+------+--------+-------+ |
49 |
| id | amount | id | weight | exist | |
50 |
+----+--------+------+--------+-------+ |
51 |
| 1 | 100 | NULL | NULL | NULL | |
52 |
| 2 | 200 | 2 | 22 | 0 | |
53 |
| 3 | 300 | NULL | NULL | NULL | |
54 |
| 4 | 400 | 4 | 44 | 1 | |
55 |
+----+--------+------+--------+-------+ |
56 |
4 rows in set (0.00 sec) |
ON 子句和 WHERE 子句有什麼不一樣?it
一個問題:下面兩個查詢的結果集有什麼不一樣麼?io
1 |
1. SELECT * FROM product LEFT JOIN product_details |
2 |
ON (product.id = product_details.id)
|
3 |
AND product_details.id=2;
|
4 |
2. SELECT * FROM product LEFT JOIN product_details |
5 |
ON (product.id = product_details.id)
|
6 |
WHERE product_details.id=2;
|
用例子來理解最好不過了:table
01 |
mysql> SELECT * FROM product LEFT JOIN product_details |
02 |
ON (product.id = product_details.id)
|
03 |
AND product_details.id=2;
|
04 |
+----+--------+------+--------+-------+ |
05 |
| id | amount | id | weight | exist | |
06 |
+----+--------+------+--------+-------+ |
07 |
| 1 | 100 | NULL | NULL | NULL | |
08 |
| 2 | 200 | 2 | 22 | 0 | |
09 |
| 3 | 300 | NULL | NULL | NULL | |
10 |
| 4 | 400 | NULL | NULL | NULL | |
11 |
+----+--------+------+--------+-------+ |
12 |
4 rows in set (0.00 sec) |
14 |
mysql> SELECT * FROM product LEFT JOIN product_details |
15 |
ON (product.id = product_details.id)
|
16 |
WHERE product_details.id=2;
|
17 |
+----+--------+----+--------+-------+ |
18 |
| id | amount | id | weight | exist | |
19 |
+----+--------+----+--------+-------+ |
20 |
| 2 | 200 | 2 | 22 | 0 | |
21 |
+----+--------+----+--------+-------+ |
22 |
1 row in set (0.01 sec) |
第一條查詢使用 ON 條件決定了從 LEFT JOIN的 product_details表中檢索符合的全部數據行。class
第二條查詢作了簡單的LEFT JOIN,而後使用 WHERE 子句從 LEFT JOIN的數據中過濾掉不符合條件的數據行。
再來看一些示例:
02 |
mysql> SELECT * FROM product LEFT JOIN product_details |
03 |
ON product.id = product_details.id
|
04 |
AND product.amount=100;
|
05 |
+----+--------+------+--------+-------+ |
06 |
| id | amount | id | weight | exist | |
07 |
+----+--------+------+--------+-------+ |
08 |
| 1 | 100 | NULL | NULL | NULL | |
09 |
| 2 | 200 | NULL | NULL | NULL | |
10 |
| 3 | 300 | NULL | NULL | NULL | |
11 |
| 4 | 400 | NULL | NULL | NULL | |
12 |
+----+--------+------+--------+-------+ |
13 |
4 rows in set (0.00 sec) |
全部來自product表的數據行都被檢索到了,但沒有在product_details表中匹配到記錄(product.id = product_details.id AND product.amount=100 條件並無匹配到任何數據)
01 |
mysql> SELECT * FROM product LEFT JOIN product_details |
02 |
ON (product.id = product_details.id)
|
03 |
AND product.amount=200;
|
04 |
+----+--------+------+--------+-------+ |
05 |
| id | amount | id | weight | exist | |
06 |
+----+--------+------+--------+-------+ |
07 |
| 1 | 100 | NULL | NULL | NULL | |
08 |
| 2 | 200 | 2 | 22 | 0 | |
09 |
| 3 | 300 | NULL | NULL | NULL | |
10 |
| 4 | 400 | NULL | NULL | NULL | |
11 |
+----+--------+------+--------+-------+ |
12 |
4 rows in set (0.01 sec) |
一樣,全部來自product表的數據行都被檢索到了,有一條數據匹配到了。
使用 WHERE ... IS NULL 子句的 LEFT JOIN
當你使用 WHERE ... IS NULL 子句時會發生什麼呢?
如前所述,WHERE 條件查詢發生在 匹配階段以後,這意味着 WHERE ... IS NULL 子句將從匹配階段後的數據中過濾掉不知足匹配條件的數據行。
紙面上看起來很清楚,可是當你在 ON 子句中使用多個條件時就會感到困惑了。
我總結了一種簡單的方式來理解上述狀況:
將 IS NULL 做爲否認匹配條件使用 !(A and B) == !A OR !B 邏輯判斷
看看下面的示例:
01 |
mysql> SELECT a.* FROM product a LEFT JOIN product_details b |
02 |
ON a.id=b.id AND b.weight!=44 AND b.exist=0
|
11 |
3 rows in set (0.00 sec) |
讓咱們檢查一下 ON 匹配子句:
1 |
(a.id=b.id) AND (b.weight!=44) AND (b.exist=0) |
咱們能夠把 IS NULL 子句 看做是否認匹配條件。
這意味着咱們將檢索到如下行:
1 |
!( exist(b.id that equals to a.id) AND b.weight !=44 AND b.exist=0 ) |
2 |
!exist(b.id that equals to a.id) || !(b.weight !=44) || !(b.exist=0) |
3 |
!exist(b.id that equals to a.id) || b.weight =44 || b.exist=1 |
就像在C語言中的邏輯 AND 和 邏輯 OR表達式同樣,其操做數是從左到右求值的。若是第一個參數作夠判斷操做結果,那麼第二個參數便不會被計算求值(短路效果)
看看別的示例:
01 |
mysql> SELECT a.* FROM product a LEFT JOIN product_details b |
02 |
ON a.id=b.id AND b.weight!=44 AND b.exist=1
|
12 |
4 rows in set (0.00 sec) |
Matching-Conditions 與 Where-conditions 之戰
若是你吧基本的查詢條件放在 ON 子句中,把剩下的否認條件放在 WHERE 子句中,那麼你會得到相同的結果。
例如,你能夠不這樣寫:
1 |
SELECT a.* FROM product a LEFT JOIN product_details b |
2 |
ON a.id=b.id AND b.weight!=44 AND b.exist=0 |
你能夠這樣寫:
1 |
SELECT a.* FROM product a LEFT JOIN product_details b |
3 |
WHERE b.id is null OR b.weight=44 OR b.exist=1 |
01 |
mysql> SELECT a.* FROM product a LEFT JOIN product_details b |
03 |
WHERE b.id is null OR b.weight=44 OR b.exist=1;
|
11 |
3 rows in set (0.00 sec) |
你能夠不這樣寫:
1 |
SELECT a.* FROM product a LEFT JOIN product_details b |
2 |
ON a.id=b.id AND b.weight!=44 AND b.exist!=0 |
能夠這樣寫:
1 |
SELECT a.* FROM product a LEFT JOIN product_details b |
3 |
WHERE b.id is null OR b.weight=44 OR b.exist=0; |
01 |
mysql> SELECT a.* FROM product a LEFT JOIN product_details b |
03 |
WHERE b.id is null OR b.weight=44 OR b.exist=0;
|
12 |
4 rows in set (0.00 sec) |
這些查詢真的效果同樣?
若是你只須要第一個表中的數據的話,這些查詢會返回相同的結果集。有一種狀況就是,若是你從 LEFT JOIN的表中檢索數據時,查詢的結果就不一樣了。
如前所屬,WHERE 子句是在匹配階段以後用來過濾的。
例如:
01 |
mysql> SELECT * FROM product a LEFT JOIN product_details b |
02 |
ON a.id=b.id AND b.weight!=44 AND b.exist=1
|
04 |
+----+--------+------+--------+-------+ |
05 |
| id | amount | id | weight | exist | |
06 |
+----+--------+------+--------+-------+ |
07 |
| 1 | 100 | NULL | NULL | NULL | |
08 |
| 2 | 200 | NULL | NULL | NULL | |
09 |
| 3 | 300 | NULL | NULL | NULL | |
10 |
| 4 | 400 | NULL | NULL | NULL | |
11 |
+----+--------+------+--------+-------+ |
12 |
4 rows in set (0.00 sec) |
14 |
mysql> SELECT * FROM product a LEFT JOIN product_details b |
16 |
WHERE b.id IS NULL OR b.weight=44 OR b.exist=0;
|
17 |
+----+--------+------+--------+-------+ |
18 |
| id | amount | id | weight | exist | |
19 |
+----+--------+------+--------+-------+ |
20 |
| 1 | 100 | NULL | NULL | NULL | |
21 |
| 2 | 200 | 2 | 22 | 0 | |
22 |
| 3 | 300 | NULL | NULL | NULL | |
23 |
| 4 | 400 | 4 | 44 | 1 | |
24 |
+----+--------+------+--------+-------+ |
25 |
4 rows in set (0.00 sec) |
總附註:
若是你使用 LEFT JOIN 來尋找在一些表中不存在的記錄,你須要作下面的測試:WHERE 部分的 col_name IS NULL(其中 col_name 列被定義爲 NOT NULL),MYSQL 在查詢到一條匹配 LEFT JOIN 條件後將中止搜索更多行(在一個特定的組合鍵下)。
----------------------------------------------------------
易銷寶(www.exiao800.com),企業專屬的的定貨平臺,網上定貨系統,加盟商定貨軟件,訂單管理系統
易銷寶(www.exiao800.com),企業專屬的的定貨平臺,網上定貨系統,加盟商定貨軟件,訂單管理系統