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 ; 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;