更新时间:2024-12-11 GMT+08:00

JOINS

允许合并多个relation的数据。

HetuEngine支持JOIN类型为:CROSS JOIN、INNER JOIN、OUTER JOIN(LEFT JOIN、RIGHT JOIN、FULL JOIN)、SEMIN JOIN和ANTI JOIN。

CROSS JOIN

CROSS JOIN返回两个关系的笛卡尔积。可以使用CROSS JOIN语法指定,也可以在FROM子句中指定多个relation。

以下的query是等价的:

SELECT * FROM nation CROSS JOIN region;
SELECT * FROM nation, region;

INNER JOIN

两个表中至少存在一个相匹配的数据时才返回行,等价于JOIN。也可以转换为等价的WHERE语句,转换方式如下:

SELECT * FROM nation (INNER) JOIN region ON nation.name=region.name;
SELECT * FROM nation ,region WHERE nation.name=region.name;

OUTER JOIN

OUTER JOIN返回符合查询条件的行的同时也返回不符合的行,分为以下三类:

  • 左外连接:LEFT JOIN或LEFT OUTER JOIN,表示以左表(nation)为基础返回左表所有的行及右表(region)中相匹配行的数据,若右表中没有匹配,则该行对应的右表的值为空。
  • 右外连接:RIGHT JOIN或RIGHT OUTER JOIN,表示以右表(region)为基础返回右表所有的行及左表(nation)中相匹配行的数据,若左表中没有匹配,则该行对应的左表的值为空。
  • 全外连接:FULL JOIN或FULL OUTER JOIN,表示只要其中某个表存在匹配,则返回相匹配的行,相当于LEFT JOIN和RIGHT JOIN结合。
SELECT * FROM nation LEFT (OUTER) JOIN region ON nation.name=region.name;
SELECT * FROM nation RIGHT (OUTER) JOIN region ON nation.name=region.name;
SELECT * FROM nation FULL (OUTER) JOIN region ON nation.name=region.name;

LATERAL

FROM中的子查询可以加上LATERAL关键字,允许引用前面FROM项提供的列:

SELECT name, x, y FROM nation CROSS JOIN LATERAL (SELECT name || ' :-' AS x) CROSS JOIN LATERAL (SELECT x || ')' AS y);

SEMI JOIN、ANTI JOIN

当一张表在另一张表找到匹配的记录之后,半连接(semi-join)返回第一张表中的记录。与条件连接相反,即使在右节点中找到几条匹配的记录,左节点的表也只会返回一条记录。另外,右节点的表一条记录也不会返回。半连接通常使用IN或EXISTS作为连接条件。

而anti-join则与semi-join相反,即当在第二张表没有发现匹配记录时,才会返回第一张表里的记录;当使用not exists/not in的时候会用到。

其他支持的条件包括如下内容:

  • where子句中的多个条件
  • 别名关系
  • 下标表达式
  • 解引用表达式
  • 强制转换表达式
  • 特定函数调用

目前,只在如下情况下支持多个semi/anti join表达式:第一个表中的列在其直接后续的join表达式中被查询,且不与其他join表达式有关系。

示例如下:

CREATE SCHEMA testing ;

USE testing;

CREATE TABLE table1(id int, name varchar,rank int);

INSERT INTO table1 VALUES(10,'sachin',1),(45,'rohit',2),(46,'rohit',3),(18,'virat',4),(25,'dhawan',5);

CREATE TABLE table2(serial int,name varchar);

INSERT INTO table2 VALUES(1,'sachin'),(2,'sachin'),(3,'rohit'),(4,'virat');

CREATE TABLE table3(serial int, name varchar,country varchar);

INSERT INTO table3 VALUES(1,'sachin','india'),(20,'bhuvi','india'),(45,'boult','newzealand'),(3,'maxwell','australia'),(45,'rohit','india'),(4,'pant','india'),(10,'KL','india'),(445,'rohit','india');

CREATE TABLE table4(id int, name varchar,rank int);

INSERT INTO table4 VALUES(10,'sachin',1),(45,'rohit',2),(46,'rohit',3),(18,'virat',4),(25,'dhawan',5);

select * from table1 left semi join table2 on table1.name=table2.name where table1.name='rohit' and table2.serial=3;
 id | name  | rank 
----|-------|------
 45 | rohit |    2 
 46 | rohit |    3 
(2 rows)


select * from table1 left anti join table2 on table1.name=table2.name where table1.name='rohit' and table2.serial=3;
 id |  name  | rank 
----|--------|------
 10 | sachin |    1 
 18 | virat  |    4 
 25 | dhawan |    5 
(3 rows)

select * from table1 right semi join table2 on table1.name=table2.name where table1.name='rohit' and table2.serial=3;
 serial | name  
--------|-------
      3 | rohit 
(1 row)

select * from table1 right anti join table2 on table1.name=table2.name where table1.name='rohit' and table2.serial=3;
 serial |  name  
--------|--------
      1 | sachin 
      2 | sachin 
      4 | virat  
(3 rows)

SELECT * FROM table1 t1 LEFT SEMI JOIN table2 t2 on t1.name=t2.name left semi join table3 t3 on t1.name = t3.name left semi join table4 t4 on t1.name=t4.name;
id | name  | rank  
----|-------|------ 
 10 | sachin |   1  
 45 | rohit |    2
 46 | rohit |    3  
(3 rows) 

Qualifying Column Names

当JOIN的两个relation有相同的列名时,列引用必须使用relation别名(如果relation有别名)或relation名称进行限定:

SELECT nation.name, region.name FROM nation CROSS JOIN region;
SELECT n.name, r.name FROM nation AS n CROSS JOIN region AS r;
SELECT n.name, r.name FROM nation n CROSS JOIN region r;