博客 / 詳情

返回

MySQL 篩選條件放 ON 後 vs 放 WHERE 後

今天我們來講講數據庫篩選條件放 ON 後和放 WHERE 後的區別。

ON 決定如何 "連接" 表,WHERE 決定連接後 "顯示" 哪些行。 這個根本區別導致了在 LEFT JOIN / RIGHT JOIN 外連接中,條件放置位置會產生巨大影響;而在 INNER JOIN 中,效果通常 等價

ON 條件匹配 被驅動表 的行,生成 "臨時關聯結果集"。LEFT JOIN 會保留 驅動表 所有行,匹配不上的 被驅動表 字段填充為 NULL

WHERE 會對 "臨時關聯結果集" 進行條件過濾,刪除不滿足的行。

接下來我們搞兩張測試表,一目瞭然。

-- 用户表(驅動表,左表)
CREATE TABLE `ysjz_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `ysjz_user` VALUES (1,'張三',18),(2,'李四',25),(3,'王五',30);

-- 訂單表(被驅動表,右表)
CREATE TABLE `ysjz_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `amount` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `ysjz_order` VALUES (1,1,100),(2,2,200),(3,2,300),(4,4,500); -- 注:user_id=4無對應用户

場景一:使用 INNER JOIN,查詢 年齡 > 20 的用户及其訂單。

寫法1:條件放 ON

SELECT u.*, o.* 
FROM `ysjz_user` u
INNER JOIN `ysjz_order` o ON u.id = o.user_id AND u.age > 20;

場景一寫法12

寫法2:條件放 WHERE

SELECT u.*, o.* 
FROM `ysjz_user` u
INNER JOIN `ysjz_order` o ON u.id = o.user_id 
WHERE u.age > 20;

場景一寫法12

兩種寫法的 結果一致寫法1 更高效,因少關聯了 年齡 ≤ 20 的用户。

場景二:使用 LEFT JOIN保留所有用户,同時顯示 年齡 > 20 的用户及其訂單(≤ 20 的用户訂單顯示為 NULL)。

寫法1:條件放 ON 後(符合要求)

SELECT u.*, o.* 
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id AND u.age > 20;

場景二寫法1

寫法2:條件放 WHERE 後(跟要求不符)

SELECT u.*, o.* 
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id
WHERE u.age > 20;

場景二寫法2

寫法2 將 張三 過濾了,並沒有 保留所有用户。

場景三:使用 LEFT JOIN保留所有用户,同時顯示 訂單金額 > 200 的訂單(無符合條件訂單的用户填充為 NULL)。

寫法1:條件放 ON 後(符合要求)

SELECT u.*, o.* 
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id AND o.amount > 200;

場景三寫法1

寫法2:條件放 WHERE 後(跟要求不符)

SELECT u.*, o.* 
FROM `ysjz_user` u
LEFT JOIN `ysjz_order` o ON u.id = o.user_id 
WHERE o.amount > 200;

場景三寫法2

寫法2 過濾了 無符合條件訂單的用户。

場景二 和 場景三 其實相差不大,只是條件作用的表不一樣。

ON 後面優先放 "表之間的關聯鍵"(如 u.id = o.user_id),非關聯的篩選條件(如 u.age > 20)是否放 ON 後,取決於是否要保留驅動表的行。

總結:ON 管關聯,WHERE 管過濾;LEFT JOIN 用 ON 保行,INNER JOIN 用 ON 提效

別人的嘴你堵不住,但自己的心卻任由自己掌控。-- 煙沙九洲

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.