子查询

最近更新时间: 2026-03-13 09:03:00

子查询是指嵌套在一个查询中的查询。TDSQL PG支持多层嵌套查询。在特定情况下,一个查询语句的条件需要从另一个查询语句中获取,内层查询(inner query)语句的查询结果,可以为外层查询(outer query)语句提供查询条件。
子查询按不同的维度,可以有不同的划分。按子查询和父查询的依赖关系划分,可以分为相关子查询和不相关子查询。
按子查询结果集划分,可以分为标量子查询,行子查询,列子查询和表子查询。

语法及关键字

语法说明

  • 子查询可以在大部分的DDL(如CREATE TABLE/VIEW)以及DML(SELECT、INSERT、UPDATE)语句中使用。
  • 子查询需要放在小括号中。
  • 子查询中的关键词可以使用 IN、ANY、SOME 和 ALL 等。

示例表

---职员信息表
CREATE TABLE EMPLOYEES(
EMPLOYEE_ID VARCHAR(100), 
NAME VARCHAR(100),
GENDER VARCHAR(6),
BIRTHDAY DATE,
EMAIL VARCHAR(100),
SALARY NUMERIC,
MANAGER_ID VARCHAR(100),
DEPARTMENT_ID VARCHAR(100));
---插入数据
INSERT INTO EMPLOYEES VALUES('0001', 'john', 'male', '1983-3-4', 'john@gmail.com', 6500, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0002', 'andy', 'male', '1987-8-9', 'andy@gmail.com', 8000, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0003', 'bob',   'male', '1985-01-04', 'bob@gmail.com', 12000, '0082', '005');
INSERT INTO EMPLOYEES VALUES('0004', 'eric',  'male', '1997-02-18', 'eric@gmail.com', 7000, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0005', 'david', 'male', '1990-6-12', 'david@gmail.com', 9000, '0082', '005');
INSERT INTO EMPLOYEES VALUES('0006', 'frank', 'male', '1982-12-19', 'frank@gmail.com', 8800, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0007', 'henry', 'male', '1993-03-04', 'henry@gmail.com', 11000, '0082', '005');
INSERT INTO EMPLOYEES VALUES('0008', 'emily', 'female', '1989-5-4', 'emily@gmail.com', 8500, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0009', 'lucy', 'female', '1992-1-3', 'lucy@gmail.com', 6500, '0081', '003');
INSERT INTO EMPLOYEES VALUES('0010', 'julia', 'female', '1991-12-30', 'julia@gmail.com', 7000, '0082', '005');
INSERT INTO EMPLOYEES VALUES('0011', 'leo', 'male', '1983-12-20', 'leo@gmail.com', 14000, '0081', '003');

相关子查询

子查询对父查询有所依赖,子查询并不能独立运行的查询。

示例1

select * from employees e1 where DEPARTMENT_ID in (select DEPARTMENT_ID from employees e2 where e2.salary < e1.salary);
 EMPLOYEE_ID | NAME  | GENDER |      BIRTHDAY       |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+---------------------+--------------+--------+------------+---------------
 0002        | andy  | male   | 1987-08-09 00:00:00 | andy@gmail.com  |   8000 | 0081       | 003
 0003        | bob   | male   | 1985-01-04 00:00:00 | bob@gmail.com   |  12000 | 0082       | 005
 0004        | eric  | male   | 1997-02-18 00:00:00 | eric@gmail.com  |   7000 | 0081       | 003
 0005        | david | male   | 1990-06-12 00:00:00 | david@gmail.com |   9000 | 0082       | 005
 0006        | frank | male   | 1982-12-19 00:00:00 | frank@gmail.com |   8800 | 0081       | 003
 0007        | henry | male   | 1993-03-04 00:00:00 | henry@gmail.com |  11000 | 0082       | 005
 0008        | emily | female | 1989-05-04 00:00:00 | emily@gmail.com |   8500 | 0081       | 003
 0011        | leo   | male   | 1983-12-20 00:00:00 | leo@gmail.com   |  14000 | 0081       | 003
(8 rows)

不相关子查询

子查询对父查询没有依赖,可以独立执行的查询。

示例2

select * from employees where gender in (select 'male' from dual);

EMPLOYEE_ID | NAME  | GENDER |      BIRTHDAY       |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+---------------------+--------------+--------+------------+---------------
 0001        | john  | male   | 1983-03-04 00:00:00 | john@gmail.com  |   6500 | 0081       | 003
 0002        | andy  | male   | 1987-08-09 00:00:00 | andy@gmail.com  |   8000 | 0081       | 003
 0003        | bob   | male   | 1985-01-04 00:00:00 | bob@gmail.com   |  12000 | 0082       | 005
 0004        | eric  | male   | 1997-02-18 00:00:00 | eric@gmail.com  |   7000 | 0081       | 003
 0005        | david | male   | 1990-06-12 00:00:00 | david@gmail.com |   9000 | 0082       | 005
 0006        | frank | male   | 1982-12-19 00:00:00 | frank@gmail.com |   8800 | 0081       | 003
 0007        | henry | male   | 1993-03-04 00:00:00 | henry@gmail.com |  11000 | 0082       | 005
 0011        | leo   | male   | 1983-12-20 00:00:00 | leo@gmail.com   |  14000 | 0081       | 003
(8 rows)

标量子查询

返回的结果集是 1 行 1 列

示例3

--查询薪水大于平均薪水的所有员工信息
select * from EMPLOYEES where salary > (select avg(salary) from EMPLOYEES);

 EMPLOYEE_ID | NAME  | GENDER |  BIRTHDAY  |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+------------+--------------+--------+------------+---------------
 0003        | bob   | male   | 1985-01-04 | bob@gmail.com   |  12000 | 0082       | 005
 0005        | david | male   | 1990-06-12 | david@gmail.com |   9000 | 0082       | 005
 0007        | henry | male   | 1993-03-04 | henry@gmail.com |  11000 | 0082       | 005
 0011        | leo   | male   | 1983-12-20 | leo@gmail.com   |  14000 | 0081       | 003
(4 rows)

行子查询

返回的结果集是 1 行 N 列

示例4

---查询与eric属于同一部门,且性别相同的所有员工信息
select * from EMPLOYEES  where (department_id, gender) = (select department_id, gender from EMPLOYEES where name = 'eric');

 EMPLOYEE_ID | NAME  | GENDER |  BIRTHDAY  |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+------------+--------------+--------+------------+---------------
 0001        | john  | male   | 1983-03-04 | john@gmail.com  |   6500 | 0081       | 003
 0002        | andy  | male   | 1987-08-09 | andy@gmail.com  |   8000 | 0081       | 003
 0004        | eric  | male   | 1997-02-18 | eric@gmail.com  |   7000 | 0081       | 003
 0006        | frank | male   | 1982-12-19 | frank@gmail.com |   8800 | 0081       | 003
 0011        | leo   | male   | 1983-12-20 | leo@gmail.com   |  14000 | 0081       | 003
(5 rows)

列子查询

返回的结果集是 N 行 1 列
列子查询通常使用 IN, ANY, ALL 和 SOME 操作符

  • IN
    返回布尔型,如果属于列表中任意一个,返回 true,否则返回 false
  • ANY
    返回布尔型,需要与比较操作符配合使用,如果集合中任意一个满足条件,返回 true,否则返回 false
  • SOME
    与 ANY 作用相同
  • ALL
    返回布尔型,需要与比较操作符配合使用,集合中所有元素满足条件才返回 true,否则返回 false

示例5

---查询名字以 d 或 f 开头的员工信息
select * from EMPLOYEES where substr(name, 1, 1) in (select 'd' union select 'f');

 EMPLOYEE_ID | NAME  | GENDER |  BIRTHDAY  |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+------------+--------------+--------+------------+---------------
 0005        | david | male   | 1990-06-12 | david@gmail.com |   9000 | 0082       | 005
 0006        | frank | male   | 1982-12-19 | frank@gmail.com |   8800 | 0081       | 003
(2 rows)

示例6

---查询工资大于 8000 或者 10000 的员工
select * from EMPLOYEES where salary > any (select 8000 union select 10000);

 EMPLOYEE_ID | NAME  | GENDER |  BIRTHDAY  |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+------------+--------------+--------+------------+---------------
 0003        | bob   | male   | 1985-01-04 | bob@gmail.com   |  12000 | 0082       | 005
 0005        | david | male   | 1990-06-12 | david@gmail.com |   9000 | 0082       | 005
 0006        | frank | male   | 1982-12-19 | frank@gmail.com |   8800 | 0081       | 003
 0007        | henry | male   | 1993-03-04 | henry@gmail.com |  11000 | 0082       | 005
 0008        | emily | female | 1989-05-04 | emily@gmail.com |   8500 | 0081       | 003
 0011        | leo   | male   | 1983-12-20 | leo@gmail.com   |  14000 | 0081       | 003
(6 rows)

示例7

---查询工资大于 8000 和 10000 的员工
select * from EMPLOYEES where salary > all (select 8000 union select 10000);
 EMPLOYEE_ID | NAME  | GENDER |  BIRTHDAY  |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+------------+--------------+--------+------------+---------------
 0003        | bob   | male   | 1985-01-04 | bob@gmail.com   |  12000 | 0082       | 005
 0007        | henry | male   | 1993-03-04 | henry@gmail.com |  11000 | 0082       | 005
 0011        | leo   | male   | 1983-12-20 | leo@gmail.com   |  14000 | 0081       | 003
(3 rows)

表子查询

返回的结果集是 N 行 N 列
表子查询与列子查询类似,区别是返回的是多列,需要与 IN, ANY, ALL 配合使用。

示例8

select * from employees where (gender, department_id) in (select 'male', 003 from dual);

 EMPLOYEE_ID | NAME  | GENDER |      BIRTHDAY       |    EMAIL     | SALARY | MANAGER_ID | DEPARTMENT_ID 
-------------+-------+--------+---------------------+--------------+--------+------------+---------------
 0001        | john  | male   | 1983-03-04 00:00:00 | john@gmail.com  |   6500 | 0081       | 003
 0002        | andy  | male   | 1987-08-09 00:00:00 | andy@gmail.com  |   8000 | 0081       | 003
 0004        | eric  | male   | 1997-02-18 00:00:00 | eric@gmail.com  |   7000 | 0081       | 003
 0006        | frank | male   | 1982-12-19 00:00:00 | frank@gmail.com |   8800 | 0081       | 003
 0011        | leo   | male   | 1983-12-20 00:00:00 | leo@gmail.com   |  14000 | 0081       | 003
(5 rows)