SQL命令 JOIN(二)
单向外部联接
IRIS支持单向外部联接:左外部联接和右外部联接。
使用标准的“inner”
联接时,当一个表的行链接到第二个表的行时,第一个表中找不到第二个表中对应行的行将从输出表中排除。
使用单向外联接时,即使第二个表中没有匹配项,第一个表中的所有行也会包括在输出表中。使用单向外连接,第一个表会从第二个表中取出相关信息,但不会因为第二个表中缺少匹配项而牺牲自己的行。
例如,如果查询首先列出Table1
并创建一个左外部联接,那么它应该能够看到Table1
中的所有行,即使它们在Table2
中没有对应的记录。
在指定单向外联接时,在FROM
子句中命名表的顺序非常重要。对于左外部联接,指定的第一个表是联接的源表。对于右外部联接,指定的第二个表是联接的源表。因此,%INORDER
或%STARTTABLE
优化关键字不能与RIGHT OUTER JOIN
一起使用。以下语法相互矛盾,导致SQLCODE-34
错误:FROM%INORDER TABLE1 RIGHT OUTER JOIN TABLE2 ON....
。
外部联接语法
IRIS支持两种表示外连接的格式:
-
ANSI
标准语法:LEFT OUTER JOIN
和RIGHT OUTER JOIN
。SQL标准语法将外联接放在SELECT
语句的FROM
子句中,而不是WHERE
子句中,如下例所示:
FROM tbl1 LEFT OUTER JOIN tbl2 ON (tbl1.key = tbl2.key)
- ODBC规范外部联接扩展语法,使用转义语法
{OJ Join-Expression}
,其中Join-Expression
是任何ANSI标准联接语法。
Null填充
单向外联接执行空值填充。这意味着,如果源表的某一行的合并列具有空值,则会为非源表中的相应字段返回空值。
左外部联接条件由以下语法表示:
代码语言:javascript复制A LEFT OUTER JOIN B ON A.x=B.y
这指定返回A
中的每一行。对于返回的每个A
行,如果有一个B
行使得A.x=B.Y
,则还将返回所有相应的B值。
如果没有A.x=B.y
的B
行,则填充空值会导致该A
行的所有B
值返回为空值。
例如,考虑包含患者信息的Patient
表,其中包括一个字段Patient
。
指定患者主治医生的DocID
和ID
代码。
数据库中的一些患者没有主诊医生,因此对这些患者记录“患者”。
DocID
字段为NULL
。
现在,我们在Patient
表和Doctor
表之间执行连接,以生成一个包含患者姓名和相应医生姓名的表。
SELECT Patient.PName,Doctor.DName
FROM Patient INNER JOIN Doctor
ON Patient.DocID=Doctor.DocID
INNER JOIN
不执行空填充。
因此,如果没有相应的医生姓名,则不会返回患者姓名。
单向外联接确实执行空值填充。因此,没有相应医生名称的患者名称将为Doctor.DName
返回NULL
。
SELECT Patient.PName,Doctor.DName
FROM Patient LEFT OUTER JOIN Doctor
ON Patient.DocID=Doctor.DocID
单向外联接条件(包括必要的空值填充)在其他条件之前应用。因此,WHERE
子句中不能由填充空值的值满足的条件(例如,B
中字段的范围或相等条件)有效地将A
和B
的单向外联接转换为常规联接(内联接)。
例如,如果将子句“WHERE Doctor.Age < 45”
添加到上面的两个“Patient”
表查询中,则它们是等效的。但是,如果添加子句“WHERE Doctor.Age < 45 OR Doctor.Age is null”
,它将保留这两个查询之间的差异。
混合外部和内部连接
IRIS支持任意顺序的混合内部连接和外部连接的所有语法。
多重连接和隐式连接的性能
默认情况下,查询优化器将多个连接操作按其对最优序列的最佳估计排序。
这不一定是在查询中指定的连接顺序。
可以在FROM
子句中指定%INORDER
、%FIRSTTABLE
或%STARTTABLE
查询优化选项,以显式指定表连接的顺序。
查询优化器可以执行子查询扁平化,将某些子查询转换为显式连接。
当子查询数量较少时,这将极大地提高连接性能。
当子查询的数量超过一个或两个时,子查询扁平化在某些情况下可能会略微降低性能。
可以在FROM
子句中指定%NOFLATTEN
查询优化选项,以显式指定不应该执行子查询扁平化。
只有当子查询扁平化后,查询中的连接总数不超过15
个连接时,查询优化器才会执行子查询扁平化。
指定超过15
个联接,如果其中一些联接是隐式联接或联接子查询,则会导致查询性能的显著下降。
示例
下面的示例显示了在表1和表2上执行JOIN
操作的结果。
Table1
Column1 | Column2 |
---|---|
aaa | bbb |
ccc | ccc |
xxx | yyy |
hhh | zzz |
Table2
Column1 | Column3 |
---|---|
ggg | hhh |
xxx | zzz |
CROSS JOIN 示例
代码语言:javascript复制SELECT * FROM Table1 CROSS JOIN Table2
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
aaa | bbb | ggg | hhh |
aaa | bbb | xxx | zzz |
ccc | ccc | ggg | hhh |
ccc | ccc | xxx | zzz |
xxx | yyy | ggg | hhh |
xxx | yyy | xxx | zzz |
hhh | zzz | ggg | hhh |
hhh | zzz | xxx | zzz |
NATURAL JOIN 示例
代码语言:javascript复制SELECT * FROM Table1 NATURAL JOIN Table2
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
xxx | yyy | xxx | zzz |
请注意,NATURAL JOIN
的 IRIS实现不会合并具有相同名称的列。
使用ON子句的INNER JOIN示例
代码语言:javascript复制SELECT * FROM Table1 INNER JOIN Table2
ON Table1.Column1=Table2.Column3
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
hhh | zzz | ggg | hhh |
使用USING子句的INNER JOIN示例
代码语言:javascript复制SELECT * FROM Table1 INNER JOIN Table2
USING (Column1)
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
xxx | yyy | xxx | zzz |
注意,USING
子句的IRIS实现不会合并具有相同名称的列。
LEFT OUTER JOIN 示例
代码语言:javascript复制SELECT * FROM Table1 LEFT OUTER JOIN Table2
ON Table1.Column1=Table2.Column3
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
aaa | bbb | null | null |
ccc | ccc | null | null |
xxx | yyy | null | null |
hhh | zzz | ggg | hhh |
RIGHT OUTER JOIN 示例
代码语言:javascript复制SELECT * FROM Table1 RIGHT OUTER JOIN Table2
ON Table1.Column1=Table2.Column3
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
hhh | zzz | ggg | hhh |
null | null | xxx | zzz |
FULL OUTER JOIN
代码语言:javascript复制SELECT * FROM Table1 FULL OUTER JOIN Table2
ON Table1.Column1=Table2.Column3
Column1 | Column2 | Column1 | Column3 |
---|---|---|---|
aaa | bbb | null | null |
ccc | ccc | null | null |
xxx | yyy | null | null |
hhh | zzz | ggg | hhh |
null | null | xxx | zzz |