-- 分類表
CREATE TABLE bro_cats (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128) NOT NULL DEFAULT '',
desn VARCHAR(128) NOT NULL DEFAULT ''
);
-- 文章表
CREATE TABLE bro_articles (
id INT PRIMARY KEY AUTO_INCREMENT,
cid INT NOT NULL,
name VARCHAR(128) NOT NULL,
content TEXT NOT NULL
);
-- 插入測試數據
INSERT INTO bro_cats (name, desn) VALUES
('php', 'php demo'),
('jsp', 'jsp demo'),
('asp', 'asp demo');
INSERT INTO bro_articles (cid, name, content) VALUES
(1, 'this article of php1', 'php content1'),
(1, 'this article of php2', 'php content2'),
(2, 'this article of jsp', 'jsp content'),
(3, 'this article of asp1', 'asp content1'),
(3, 'this article of asp2', 'asp content2');
| 類型 | SQL | 結果行數 | 語義 |
|---|---|---|---|
| INNER JOIN | SELECT c.name AS cat, a.name AS art FROM bro_cats c JOIN bro_articles a ON c.id = a.cid; |
5 | 僅返回雙方都匹配的行(交集) |
| LEFT JOIN | SELECT c.name AS cat, a.name AS art FROM bro_cats c LEFT JOIN bro_articles a ON c.id = a.cid; |
5 | 以左表為主,無匹配時右表列為 NULL |
| RIGHT JOIN | SELECT c.name AS cat, a.name AS art FROM bro_cats c RIGHT JOIN bro_articles a ON c.id = a.cid; |
5 | 以右表為主,無匹配時左表列為 NULL |
本例中:每個分類至少有一篇文章,三種 JOIN 結果行數相同,但語義不同。若插入一個無文章的分類,LEFT JOIN 會多出一行 art=NULL。
ON 決定關聯方式,WHERE 過濾結果集;LEFT JOIN ... ON ... WHERE right.col IS NULL 可查「無匹配行」。cid、id)務必建索引,複合索引覆蓋 SELECT 列可避免回表。
SELECT u.name, c.title, cat.name AS category
FROM users u
JOIN comments c ON u.id = c.uid
JOIN articles a ON c.aid = a.id
JOIN categories cat ON a.cid = cat.id
WHERE u.status = 1;
驅動表選擇原則:過濾後行數最少的表優先驅動,配合 EXPLAIN 驗證 type=ref、rows 最小。
作者:You_Can