What is the difference between LATERAL and a subquery in PostgreSQL?
由于Postgres能够进行
我知道
更像是相关的子查询
这个相关的答案有两个并排的代码示例,解决了同样的问题:
- 优化GROUP BY查询以检索每个用户的最新行
对于返回多个列,
另外,请记住相关子查询的等价物是
- 多次调用带有数组参数的set-returns函数
阅读
它比我们在这里提出的任何答案更具权威性:
- https://www.postgresql.org/docs/current/static/queries-table-expressions.html#QUERIES-LATERAL
- http://www.postgresql.org/docs/current/static/sql-select.html
子查询无法做到的事情
有一些
This is only allowed in the
FROM clause;
所以这可行,但不能轻易用子查询替换:
1 2 | CREATE TABLE tbl (a1 INT[], a2 INT[]); SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2); -- implicit LATERAL |
表函数自动采用
更多关于
- 如何声明set-returning-function只允许在FROM子句中使用?
在
您也可以直接在
- SELECT子句中多个set-returns函数的预期行为是什么?
以上面的例子为基础:
1 2 | SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2 FROM tbl; |
比较:
dbfiddle for pg 9.6 here
dbfiddle for pg 10 here
澄清错误信息
手册:
For the
INNER andOUTER join types, a join condition must be
specified, namely exactly one ofNATURAL ,ON join_condition,
orUSING (join_column [, ...]). See below for the meaning.
ForCROSS JOIN , none of these clauses can appear.
所以这两个查询是有效的(即使不是特别有用):
1 2 3 4 5 6 | SELECT * FROM tbl t LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE; SELECT * FROM tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t; |
虽然这个不是:
1 2 3 | <strike>SELECT * FROM tbl t LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;</strike> |
这就是为什么@Andomar的代码示例是正确的( strike>无效。
非
1 2 3 4 5 6 7 8 | SELECT * FROM table1 t1 CROSS JOIN lateral ( SELECT * FROM t2 WHERE t1.col1 = t2.col1 -- Only allowed because of lateral ) sub |
这种"向外看"意味着必须对子查询进行多次评估。毕竟,
相比之下,非
1 2 3 4 5 6 7 8 | SELECT * FROM table1 t1 CROSS JOIN ( SELECT * FROM t2 WHERE t2.col1 = 42 -- No reference to outer query ) sub |
如果没有
首先,横向和交叉应用是一回事。因此,您也可以阅读Cross Apply。由于它在SQL Server中实现了很长时间,因此您可以在Lateral中找到有关它的更多信息。
其次,根据我的理解,使用子查询而不是使用横向,没有什么是你无法做到的。但:
考虑以下查询。
1 2 3 4 | SELECT A.* , (SELECT B.Column1 FROM B WHERE B.Fk1 = A.PK AND LIMIT 1) , (SELECT B.Column2 FROM B WHERE B.Fk1 = A.PK AND LIMIT 1) FROM A |
在这种情况下你可以使用横向。
1 2 3 4 5 6 | SELECT A.* , x.Column1 , x.Column2 FROM A LEFT JOIN LATERAL ( SELECT B.Column1,B.Column2,B.Fk1 FROM B LIMIT 1 ) x ON X.Fk1 = A.PK |
在此查询中,由于limit子句,您无法使用普通连接。
当没有简单的连接条件时,可以使用横向或交叉应用。
横向或交叉应用有更多用途,但这是我发现的最常见的用法。
没有人指出的一件事是你可以使用
例如:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE OR REPLACE FUNCTION delete_company(companyId VARCHAR(255)) RETURNS void AS $$ BEGIN DELETE FROM company_settings WHERE"company_id"=company_id; DELETE FROM users WHERE"company_id"=companyId; DELETE FROM companies WHERE id=companyId; END; $$ LANGUAGE plpgsql; SELECT * FROM ( SELECT id, name, created_at FROM companies WHERE created_at < '2018-01-01' ) c, LATERAL delete_company(c.id); |
这是我知道如何在PostgreSQL中做这种事情的唯一方法。