全部产品

子查询

更新时间:2020-04-08 18:22:44

子查询指的是 SELECT 查询语句中嵌套了另一个或者多个 SELECT 语句,可以返回单行结果、多行结果或不返回结果。SELECT 语句的 FROM 子句中的子查询也称为内联视图。您可以在嵌入式视图中嵌套任意数量的子查询。SELECT 语句的 WHERE 子句中的子查询也称为嵌套子查询。

子查询可以分成有依赖关系的子查询和没有依赖关系的子查询。有依赖关系的子查询是指该子查询的执行依赖了外部查询的变量,所以这种子查询通常会被计算多次。没有依赖关系的子查询是指该子查询的执行不依赖外部查询的变量,这种子查询一般只需要计算一次。子查询按类型可分为:

  • 单行子查询,不向外部返回结果,或者只返回一行结果。
  • 多行子查询,向外部返回零行、一行或者多行结果。

语法

  1. SELECT [ hint ] [ { { DISTINCT | UNIQUE } | ALL } ] select_list
  2. FROM { table_reference | join_clause | ( join_clause ) }
  3. [ , { table_reference | join_clause | (join_clause) } ]
  4. [ where_clause ]
  5. [ hierarchical_query_clause ]
  6. [ group_by_clause ]
  7. | subquery { UNION [ALL] | INTERSECT | MINUS } subquery [ { UNION [ALL] | INTERSECT | MINUS } subquery ]
  8. | ( subquery ) [ order_by_clause ] [ row_limiting_clause ]

参数

参数 说明
select_list 查询列表。
subquery 子查询。
hint 注释。
table_reference 要查询的目标表。

如果子查询中的列与包含语句中的列具有相同的名称,则必须在包含语句中对表列的任何引用之前加上表名或别名。您可以将子查询中的列与表、视图或实例视图的名称或别名进行限定。

当嵌套子查询引用来自引用到子查询上方一个级别的父语句的表的列时,OceanBase 执行相关的子查询。父语句可以是嵌套子查询的选择、更新或删除语句。Hint 可以选择重写查询作为连接,或者使用其他技术来制定语义等效的查询。OceanBase 通过查看子查询中命名的表,然后在父语句中命名的表中查找子查询中的不合格列,从而解析子查询中的不合格列。

当嵌套的子查询引用表中的列时,OceanBase 会执行相关的子查询,该表引用了子查询上一级的父语句。父查询语句可以是子查询嵌套在其中的 SELECTUPDATEDELETE 语句。从概念上讲,对关联的子查询对父查询语句处理的每一行都进行一次评估。但是,Hint 可以选择将查询重写为联接,也可以使用其他某种技术来制定语义上等效的查询。OceanBase 通过在子查询中命名的表然后在父语句中命名的表中查找子查询中的非限定列。相关子查询回答一个多部分问题,其答案取决于父语句处理的每一行中的值。

以下语句会用到子查询:

  • 定义要插入到 INSERTCREATE TABLE 语句的目标表中的行集。
  • CREATE VIEWCREATE MATERIALIZED VIEW 语句中定义要包含在视图或实例化视图中的行集。
  • UPDATE 中定义要分配给现有行的一个或多个值。
  • WHERE 子句,HAVING 子句或 START WITH 中提供条件值 SELECTUPDATEDELETE 语句的子句。
  • 定义包含查询操作的表。

嵌套子查询的展开(Unnesting of Nested Subqueries)

嵌套子查询展开是数据库的一种优化策略,它把一些子查询置于外层的父查询中,其实质是把某些子查询转化为等价的多表连接操作。这种策略带来的一个明显的好处是写访问路径、连接方法和连接顺序可能被有效的利用,使得查询语句的层次尽可能的减少。

Hint 将自动取消以下嵌套子查询:

  • 不相关的 IN 子查询。
  • 只要 INEXISTS 相关子查询不包含聚合函数或 GROUP BY 子句。
  • 您可以通过指示 Hint 来启用扩展子查询。
  • 您可以通过指定 HASH_AJ 来取消嵌套不相关的 NOT IN 子查询中的 MERGE_AJ 提示。
  • 您可以通过在子查询中指定 UNNEST 提示来取消嵌套其他子查询。

分布式查询

您可以使用 OceanBase 客户端远程访问 OceanBase 分布式数据库里的数据。

示例

以下语句创建了表 table_a和表 table_b,并向表中插入数据:

  1. CREATE TABLE table_a(PK INT, name VARCHAR(25));
  2. INSERT INTO table_a VALUES(1,'福克斯');
  3. INSERT INTO table_a VALUES(2,'警察');
  4. INSERT INTO table_a VALUES(3,'的士');
  5. INSERT INTO table_a VALUES(4,'林肯');
  6. INSERT INTO table_a VALUES(5,'亚利桑那州');
  7. INSERT INTO table_a VALUES(6,'华盛顿');
  8. INSERT INTO table_a VALUES(7,'戴尔');
  9. INSERT INTO table_a VALUES(10,'朗讯');
  10. CREATE TABLE table_b(PK INT, name VARCHAR(25));
  11. INSERT INTO table_b VALUES(1,'福克斯');
  12. INSERT INTO table_b VALUES(2,'警察');
  13. INSERT INTO table_b VALUES(3,'的士');
  14. INSERT INTO table_b VALUES(6,'华盛顿');
  15. INSERT INTO table_b VALUES(7,'戴尔');
  16. INSERT INTO table_b VALUES(8,'微软');
  17. INSERT INTO table_b VALUES(9,'苹果');
  18. INSERT INTO table_b VALUES(11,'苏格兰威士忌');

没有依赖关系的子查询,执行以下语句:

  1. SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.PK FROM TABLE_B T2);

查询结果如下:

  1. +------+-----------+
  2. | PK | NAME |
  3. +------+-----------+
  4. | 1 | 福克斯 |
  5. | 2 | 警察 |
  6. | 3 | 的士 |
  7. | 6 | 华盛顿 |
  8. | 7 | 戴尔 |
  9. +------+-----------+

有依赖关系的子查询,子查询中用到了外层查询变量 T1.PK,执行以下语句:

  1. SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.PK FROM TABLE_B T2 WHERE T2.PK = T1.PK);

查询结果如下:

  1. +------+-----------+
  2. | PK | NAME |
  3. +------+-----------+
  4. | 1 | 福克斯 |
  5. | 2 | 警察 |
  6. | 3 | 的士 |
  7. | 6 | 华盛顿 |
  8. | 7 | 戴尔 |
  9. +------+-----------+

有依赖关系的子查询被展开改写成连接,执行以下语句:

  1. EXPLAIN SELECT * FROM TABLE_A T1 WHERE T1.PK IN (SELECT T2.NAME FROM TABLE_B T2 WHERE T2.NAME = T1.NAME);

查询结果如下:

  1. +------------------------------------+
  2. | Query Plan |
  3. +------------------------------------+
  4. =============================================
  5. |ID|OPERATOR |NAME|EST. ROWS|COST|
  6. ---------------------------------------------
  7. |0 |HASH RIGHT SEMI JOIN| |8 |107 |
  8. |1 | TABLE SCAN |T2 |8 |38 |
  9. |2 | TABLE SCAN |T1 |8 |38 |
  10. =============================================
  11. Outputs & filters:
  12. -------------------------------------
  13. 0 - output([T1.PK], [T1.NAME]), filter(nil),
  14. equal_conds([T1.PK = T2.NAME], [T2.NAME = T1.NAME]), other_conds(nil)
  15. 1 - output([T2.NAME]), filter(nil),
  16. access([T2.NAME]), partitions(p0)
  17. 2 - output([T1.NAME], [T1.PK]), filter(nil),
  18. access([T1.NAME], [T1.PK]), partitions(p0)
  19. +------------------------------------+