Skip to content

PostgreSQL 子查询

概述

子查询(Subquery)是嵌套在其他 SQL 查询中的查询语句。子查询可以出现在 WHEREFROMSELECT 等子句中,根据使用场景可以返回单个值、单行或多行结果。子查询使得复杂的数据检索逻辑可以在一条 SQL 语句中完成。

WHERE 子查询

IN 子查询

IN 用于检查某个值是否存在于子查询返回的结果集中:

sql
-- 查询属于"电子产品"分类的所有商品
SELECT * FROM products
WHERE category_id IN (
    SELECT id FROM categories WHERE name = 'Electronics'
);

NOT IN 子查询

NOT IN 用于排除子查询返回结果中的值:

sql
-- 查询没有取消订单的用户
SELECT * FROM users
WHERE id NOT IN (
    SELECT user_id FROM orders WHERE status = 'cancelled'
);

注意

当子查询结果中包含 NULL 值时,NOT IN 会返回空结果集。此时应改用 NOT EXISTS

EXISTS 子查询

EXISTS 用于检查子查询是否返回至少一行数据:

sql
-- 查询至少有一笔订单的用户
SELECT * FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

NOT EXISTS 子查询

NOT EXISTS 用于检查子查询是否不返回任何数据:

sql
-- 查询没有任何评价的商品
SELECT * FROM products p
WHERE NOT EXISTS (
    SELECT 1 FROM reviews r WHERE r.product_id = p.id
);

ANY / SOME 子查询

ANY(或 SOME)用于将值与子查询返回的任意一个值进行比较,只要满足其中一个条件即为真:

sql
-- 查询价格高于任一分类平均价格的商品
SELECT * FROM products
WHERE price > ANY (
    SELECT AVG(price) FROM products GROUP BY category
);

ALL 子查询

ALL 用于将值与子查询返回的所有值进行比较,必须满足全部条件才为真:

sql
-- 查询价格高于所有分类最高价格的商品
SELECT * FROM products
WHERE price > ALL (
    SELECT MAX(price) FROM products GROUP BY category
);

FROM 子查询(派生表)

子查询可以放在 FROM 子句中作为临时表(也称为派生表或内联视图)使用:

sql
-- 查询商品数量超过10的分类统计信息
SELECT * FROM (
    SELECT
        category,
        COUNT(*) AS product_count,
        AVG(price) AS avg_price
    FROM products
    GROUP BY category
) AS category_stats
WHERE product_count > 10;

提示

FROM 子句中的子查询必须使用 AS 指定别名。

SELECT 子查询(标量子查询)

子查询可以放在 SELECT 子句中,作为计算列使用。此时子查询必须返回单个值(标量值):

sql
-- 查询每个用户及其订单数量
SELECT
    name,
    (SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
FROM users;

相关子查询

相关子查询(Correlated Subquery)是指子查询引用了外部查询的列。每处理外部查询的一行数据,子查询都会重新执行一次:

sql
-- 查询有大额订单(金额超过1000)的用户
SELECT u.* FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o
    WHERE o.user_id = u.id
    AND o.total > 1000
);
sql
-- 查询每个分类中价格最高的商品
SELECT p.* FROM products p
WHERE p.price = (
    SELECT MAX(price)
    FROM products
    WHERE category = p.category
);

小结

子查询要点:

  • WHERE 子句中可使用 INEXISTSANYALL 等操作符
  • FROM 子句中的子查询作为派生表使用,必须指定别名
  • SELECT 子句中的标量子查询用于计算列,必须返回单个值
  • 相关子查询引用外部查询的列,每行都会重新执行
  • NOT IN 遇到 NULL 值时行为特殊,建议优先使用 NOT EXISTS