更新时间:2024-08-20 GMT+08:00

子查询

一个查询可以嵌套在另一个查询中,其结果作为另一个查询的数据来源或判断条件。其中外层查询也叫父查询,内层查询也叫子查询。

  • 按照子查询的返回记录数分类可分为单行子查询,多行子查询。
  • 按照子查询是否被执行多次分类可分为关联子查询,非关联子查询。

单行子查询

单行子查询操作符有>=、>、<=、<、<>。

-- 创建学生表并插入数据。
gaussdb=# CREATE TABLE student(
    sid VARCHAR(5),     -- 学号
    grade INT,          -- 年级
    name VARCHAR(20),   -- 姓名
    height INT          -- 身高
);
gaussdb=# INSERT INTO student VALUES ('00001',1,'Scott',135),('00002',1,'Jack',95),('00003',1,'Ben',100);
gaussdb=# INSERT INTO student VALUES ('00004',2,'Henry',115),('00005',2,'Jordan',130),('00006',2,'Bob',126);
gaussdb=# INSERT INTO student VALUES ('00007',3,'Bella',128),('00008',3,'Alicia',136);
-- 创建老师表并插入数据。
gaussdb=# CREATE TABLE teacher (
    name VARCHAR(20),    -- 教师姓名
    grade INT            -- 班级
);
-- 插入数据。
gaussdb=# INSERT INTO teacher VALUES ('Bill',1),('Sally',2),('Luke',3);

-- 查询出身高比Bella高的学生。
gaussdb=# SELECT * FROM student
WHERE height > (SELECT height FROM student WHERE name = 'Bella');
  sid  | grade |  name  | height 
-------+-------+--------+--------
 00001 |     1 | Scott  |    135
 00005 |     2 | Jordan |    130
 00008 |     3 | Alicia |    136
(3 rows)

多行子查询

多行子查询操作符:

  • in:等于列表中的任意一个。
  • any:需要和单行比较符一起使用,和子查询返回的任意值比较。
  • all:需要和单行比较符一起使用,和子查询返回的所有值比较。
  • some:any的别名,作用相同。

示例:查询出Sally和Luke的学生

gaussdb=# SELECT * FROM student t1 WHERE t1.grade IN (
    SELECT grade FROM teacher WHERE name = 'Sally' OR name = 'Luke'
);
  sid  | grade |  name  | height 
-------+-------+--------+--------
 00004 |     2 | Henry  |    115
 00005 |     2 | Jordan |    130
 00006 |     2 | Bob    |    126
 00007 |     3 | Bella  |    128
 00008 |     3 | Alicia |    136
(5 rows)

示例:查询出2年级比3年级任意一个人都高的学生

gaussdb=# SELECT * FROM student
WHERE grade = 2 AND 
      height > ANY (SELECT height FROM student WHERE grade = 3);
  sid  | grade |  name  | height 
-------+-------+--------+--------
 00005 |     2 | Jordan |    130
(1 row)

--查询结果相当于:
gaussdb=# SELECT * FROM student
WHERE grade = 2 AND 
      height > (SELECT MIN(height) FROM student WHERE grade = 3);

示例:查询出1年级比2年级所有人都高的学生

gaussdb=# SELECT * FROM student
WHERE grade = 1 AND
      height > ALL (SELECT height FROM student WHERE grade = 2);
  sid  | grade | name  | height 
-------+-------+-------+--------
 00001 |     1 | Scott |    135
(1 row)

--查询结果相当于:
gaussdb=# SELECT * FROM student
WHERE grade = 1 AND 
      height > (SELECT MAX(height) FROM student WHERE grade = 2);

关联子查询

特点:子查询不能单独运行,是和父查询相关的。先执行父查询,再执行子查询。每执行一次父查询,子查询都要重新计算一次。

示例:查询身高大于本班级平均身高的学生

gaussdb=# SELECT * FROM student out
WHERE height > (SELECT AVG(height) FROM student
                WHERE grade = out.grade);
  sid  | grade |  name  | height 
-------+-------+--------+--------
 00001 |     1 | Scott  |    135
 00005 |     2 | Jordan |    130
 00006 |     2 | Bob    |    126
 00008 |     3 | Alicia |    136
(4 rows)

非关联子查询

特点:子查询先将值查询出来,再返回给外层查询。

示例:查询身高大于本班级平均身高的学生。

gaussdb=# SELECT t1.* 
FROM student t1,
     (SELECT grade, AVG(height) avg_hei FROM student GROUP BY grade) t2
WHERE t1.grade = t2.grade AND 
      t1.height > t2.avg_hei;
  sid  | grade |  name  | height 
-------+-------+--------+--------
 00001 |     1 | Scott  |    135
 00005 |     2 | Jordan |    130
 00006 |     2 | Bob    |    126
 00008 |     3 | Alicia |    136
(4 rows)
-- 删除
gaussdb=# DROP TABLE student;
gaussdb=# DROP TABLE teacher;