400-090-9964


博客 | 论坛

教学文章

PostgreSQL教程-查询-FROM子句-LATERAL子查询

时间:2022-01-06 来源:

7.2.1.5. LATERAL子查询

可以在出现于FROM中的子查询前放置关键词LATERAL。这允许它们引用前面的FROM项提供的列(如果没有LATERAL,每一个子查询将被独立计算,并且因此不能被其他FROM项交叉引用)。

出现在FROM中的表函数的前面也可以被放上关键词LATERAL,但对于函数该关键词是可选的,在任何情况下函数的参数都可以包含对前面的FROM项提供的列的引用。

一个LATERAL项可以出现在FROM列表顶层,或者出现在一个JOIN树中。在后一种情况下,如果它出现在JOIN的右部,那么它也可以引用 在JOIN左部的任何项。

如果一个FROM项包含LATERAL交叉引用,计算过程如下:对于提供交叉引用列的FROM项的每一行,或者多个提供这些列的多个FROM项的行集合,LATERAL项将被使用该行或者行集中的列值进行计算。得到的结果行将和它们被计算出来的行进行正常的连接。对于来自这些列的源表的每一行或行集,该过程将重复。

LATERAL的一个简单例子:

SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss;

这不是非常有用,因为它和一种更简单的形式得到的结果完全一样:

SELECT * FROM foo, bar WHERE bar.id = foo.bar_id;

在必须要使用交叉引用列来计算那些即将要被连接的行时,LATERAL是最有用的。一种常用的应用是为一个返回集合的函数提供一个参数值。例如,假设vertices(polygon)返回一个多边形的顶点集合,我们可以这样标识存储在一个表中的多边形中靠近的顶点:

SELECT p1.id, p2.id, v1, v2

FROM polygons p1, polygons p2,

LATERAL vertices(p1.poly) v1,

LATERAL vertices(p2.poly) v2

WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;

这个查询也可以被写成:

SELECT p1.id, p2.id, v1, v2

FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1,

polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2

WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;

或者写成其他几种等价的公式(正如以上提到的,LATERAL关键词在这个例子中并不是必不可少的,但是我们在这里使用它是为了使表述更清晰)。

有时候也会很特别地把LEFT JOIN放在一个LATERAL子查询的前面,这样即使LATERAL子查询对源行不产生行,源行也会出现在结果中。例如,如果get_product_names()返回一个制造商制造的产品的名字,但是某些制造商在我们的表中目前没有制造产品,我们可以找出哪些制造商是这样:

SELECT m.name

FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true

WHERE pname IS NULL;

版权所有@北京优技教育技术有限公司(CUUG,中国UNIX用户协会) Copyright 2017 ALL Rights Reserved 京ICP备11008061号-1

CUUG旗下网站:www.cuug.com.cn www.cuug.com oracle.cuug.com bbs.cuug.com bd.cuug.com

电话:010-59426307 010-59426319 邮政编码:100089

海淀校区:北京市海淀区紫竹院路88号紫竹花园4号楼D座703(CUUG)

关闭