msyqlleftjoinon後面多個條件

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,
04 PRIMARY KEY (`id`)
05 ) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
06  
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,
11 PRIMARY KEY (`id`)
12 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
13  
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
18  
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
23  
24 mysql> SELECT * FROM product;
25 +----+--------+
26 | id | amount |
27 +----+--------+
28 | 1 | 100 |
29 | 2 | 200 |
30 | 3 | 300 |
31 | 4 | 400 |
32 +----+--------+
33 4 rows in set (0.00 sec)
34  
35 mysql> SELECT * FROM product_details;
36 +----+--------+-------+
37 | id | weight | exist |
38 +----+--------+-------+
39 | 2 | 22 | 0 |
40 | 4 | 44 | 1 |
41 | 5 | 55 | 0 |
42 | 6 | 66 | 1 |
43 +----+--------+-------+
44 4 rows in set (0.00 sec)
45  
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)
13  
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的數據中過濾掉不符合條件的數據行。

再來看一些示例:

01 mysql>
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
03 WHERE b.id IS NULL;
04 +----+--------+
05 | id | amount |
06 +----+--------+
07 | 1 | 100 |
08 | 3 | 300 |
09 | 4 | 400 |
10 +----+--------+
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
03 WHERE b.id IS NULL;
04 +----+--------+
05 | id | amount |
06 +----+--------+
07 | 1 | 100 |
08 | 2 | 200 |
09 | 3 | 300 |
10 | 4 | 400 |
11 +----+--------+
12 4 rows in set (0.00 sec)

Matching-ConditionsWhere-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
3 WHERE b.id IS NULL;

你能夠這樣寫:

1 SELECT a.* FROM product a LEFT JOIN product_details b
2 ON a.id=b.id
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
02 ON a.id=b.id
03 WHERE b.id is null OR b.weight=44 OR b.exist=1;
04 +----+--------+
05 | id | amount |
06 +----+--------+
07 | 1 | 100 |
08 | 3 | 300 |
09 | 4 | 400 |
10 +----+--------+
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
3 WHERE b.id IS NULL;

能夠這樣寫:

1 SELECT a.* FROM product a LEFT JOIN product_details b
2 ON a.id=b.id
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
02 ON a.id=b.id
03 WHERE b.id is null OR b.weight=44 OR b.exist=0;
04 +----+--------+
05 | id | amount |
06 +----+--------+
07 | 1 | 100 |
08 | 2 | 200 |
09 | 3 | 300 |
10 | 4 | 400 |
11 +----+--------+
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
03 WHERE b.id is null;
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)
13  
14 mysql> SELECT * FROM product a LEFT JOIN product_details b
15 ON a.id=b.id
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),企業專屬的的定貨平臺,網上定貨系統,加盟商定貨軟件,訂單管理系統
相關文章
相關標籤/搜索