MySQL 的子查詢(xún)(Subquery)是嵌套在其他 SQL 語(yǔ)句中的查詢(xún),也稱(chēng)為內(nèi)部查詢(xún),而包含子查詢(xún)的語(yǔ)句稱(chēng)為外部查詢(xún)。子查詢(xún)可以讓 SQL 語(yǔ)句更靈活,用于過(guò)濾、計(jì)算或生成臨時(shí)數(shù)據(jù)。
子查詢(xún)通常放在在 SELECT、INSERT、UPDATE、DELETE 等語(yǔ)句中,用括號(hào) () 包裹:
外部查詢(xún) (SELECT 列 FROM 表 WHERE 條件);
子查詢(xún)返回單個(gè)值或一組值,用于 WHERE 條件判斷。
示例 1:返回單個(gè)值(單行子查詢(xún))
SELECT name, department
FROM employees
WHERE department = (
SELECT department FROM employees WHERE id = 1
);
示例 2:返回多個(gè)值(多行子查詢(xún))
使用 IN、ANY、ALL 等關(guān)鍵字:
SELECT * FROM orders
WHERE employee_id IN (
SELECT id FROM employees WHERE department IN ('銷(xiāo)售部', '市場(chǎng)部')
);
子查詢(xún)返回單個(gè)值,作為主查詢(xún)結(jié)果集中的一列。
SELECT
id,
name,
(SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
FROM users;
子查詢(xún)返回結(jié)果集,作為主查詢(xún)的數(shù)據(jù)源(需給子查詢(xún)起別名)。
SELECT
dept_avg.department,
dept_avg.avg_salary,
dept_count.emp_count
FROM
(SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department) AS dept_avg
JOIN
(SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department) AS dept_count
ON dept_avg.department = dept_count.department;
SELECT department, COUNT(*) AS emp_count
FROM employees
GROUP BY department
HAVING COUNT(*) > (
SELECT AVG(emp_count)
FROM (SELECT COUNT(*) AS emp_count FROM employees GROUP BY department) AS dept_counts
);
子查詢(xún)中引用了外部查詢(xún)的列,每行數(shù)據(jù)單獨(dú)執(zhí)行一次子查詢(xún)。
SELECT name, department, salary
FROM employees e1
WHERE salary > (
SELECT AVG(salary)
FROM employees e2
WHERE e1.department = e2.department
);
-
性能問(wèn)題:復(fù)雜的子查詢(xún)(尤其是關(guān)聯(lián)子查詢(xún))可能導(dǎo)致性能下降,可考慮用
JOIN 替代。
-
返回值限制:
-
若子查詢(xún)用在
=、> 等比較符后,必須返回單個(gè)值(單行單列)。
-
若用
IN,子查詢(xún)可返回多行單列。
-
可讀性:嵌套過(guò)深的子查詢(xún)(如 3 層以上)建議拆分或用 CTE(公用表表達(dá)式)優(yōu)化。
-
關(guān)鍵字支持:部分子查詢(xún)中不能使用
LIMIT、FOR UPDATE 等關(guān)鍵字。
多數(shù)情況下,子查詢(xún)和 JOIN 可以實(shí)現(xiàn)相同功能,但:
-
子查詢(xún)更直觀,適合簡(jiǎn)單邏輯。
-
JOIN 通常性能更好,適合復(fù)雜關(guān)聯(lián)查詢(xún)。
例如,前文的部門(mén)用戶(hù)查詢(xún)可用 JOIN 改寫(xiě):
SELECT e1.name, e1.department
FROM employees e1
JOIN employees e2 ON e1.department = e2.department
WHERE e2.id = 1 AND e1.id != 1;
根據(jù)實(shí)際場(chǎng)景選擇合適的方式,優(yōu)先保證可讀性和性能。