- PostgreSQL修炼之道:从小工到专家(第2版)
- 唐成
- 779字
- 2021-04-04 13:59:15
3.4.6 子查询
当一个查询是另一个查询的条件时,称之为子查询。主要有4种语法的子查询:
·带有谓词IN的子查询:expression [NOT] IN (sqlstatement)。
·带有EXISTS谓词的子查询:[NOT] EXISTS (sqlstatement)。
·带有比较运算符的子查询:comparison(>,<,=,!=)(sqlstatement)。
·带有ANY(SOME)或ALL谓词的子查询:comparison [ANY|ALL|SOME] (sqlstatement)。
我们还用前面例子中班级表“class”和学生表“studtent”中的数据。
下面用带有谓词IN的子查询来查询“初二(1)班”的学生记录:
osdba=# SELECT * FROM student WHERE class_no in (select no FROM class where class_name = '初二(1)班'); no | student_name | age | class_no ----+--------------+-----+---------- 1 | 张三 | 14 | 1 2 | 吴二 | 15 | 1 (2 rows)
上面的查询也可以用带EXISTS谓词的子查询来实现:
osdba=# SELECT * FROM student s WHERE EXISTS (SELECT 1 FROM class c WHERE s.class_no=c.no AND c.class_name = '初二(1)班'); no | student_name | age | class_no ----+--------------+-----+---------- 1 | 张三 | 14 | 1 2 | 吴二 | 15 | 1 (2 rows)
此查询还可以用带有比较符(这里用的是“=”)的子查询来实现:
osdba=# SELECT * FROM student WHERE class_no = (SELECT no FROM class c WHERE class_name = '初二(1)班'); no | student_name | age | class_no ----+--------------+-----+---------- 1 | 张三 | 14 | 1 2 | 吴二 | 15 | 1 (2 rows)
此查询还可以用带有ANY(SOME)或ALL谓词的子查询来实现:
osdba=# SELECT * FROM student WHERE class_no = any(SELECT no FROM class c WHERE class_name = '初二(1)班'); no | student_name | age | class_no ----+--------------+-----+---------- 1 | 张三 | 14 | 1 2 | 吴二 | 15 | 1 (2 rows)
但如果我们要查询两个班级的学生记录,不能使用带有等于“=”比较符的子查询:
osdba=# SELECT * FROM student WHERE no = (SELECT no FROM class c WHERE class_name in ('初二(1)班', '初二(2)班')); ERROR: more than one row returned by a subquery used as an expression
上面的查询报错说子查询不能返回多行。这种不能返回多行的子查询也称标量子查询,标量子查询不仅能嵌套在WHERE子句中,也可以嵌套在SELECT的列表中,如我们要查询每个班级学生的最大年龄,则可以用如下SQL语句:
osdba=# SELECT no, class_name, (SELECT max(age) as max_age FROM student s WHERE s.no= c.no) as max_age FROM class c; no | class_name | max_age ----+------------+--------- 1 | 初二(1)班 | 14 2 | 初二(2)班 | 15 3 | 初二(3)班 | 13 4 | 初二(4)班 | 15 (4 rows)
查询两个班级的学生记录时用带有ANY(SOME)谓词的子查询就没有问题了,示例如下:
osdba=# SELECT * FROM student WHERE class_no = any(SELECT no FROM class c WHERE class_name in ('初二(1)班', '初二(2)班')); no | student_name | age | class_no ----+--------------+-----+---------- 1 | 张三 | 14 | 1 2 | 吴二 | 15 | 1 3 | 李四 | 13 | 2 4 | 吴三 | 15 | 2 (4 rows)