pgsql中的lateral

  • 什么是LATERAL
  • 带有LATERAL的SQL的计算步骤
  • LATERAL在OUTER JOIN中的使用限制(或定义限制)
  • LATERAL的几个简单的例子
  • 总结

举几个我经常使用的栗子

首先说下场景:
有个一个商品表goods,还有一个评价表evaluations。商品表和评价表是一对多的。
1、在一个后台,我想查询商品的信息,同时查询这个商品的评价的数量。
我们可以通过这样来实现

SELECT
g.*,
COUNT(e.*) as num
FROM goods as g
LEFT JOIN evaluation as e on e.goods_id=g.id
WHERE = GROUP BY g.id

通过左连接,加上分组就能实现了
那么也可以使用lateral来实现

SELECT
g.*,
e.num
FROM goods as g
LEFT JOIN LATERAL(
SELECT COUNT(ev.id) as num FROM evaluation AS ev
WHERE ev.goods_id=g.id
) AS e ON TRUE
WHERE =

就这样好像lateral的优势不是那么明显。
2、我们查询评论数目大于3的商品的信息

SELECT
g.*,
COUNT(e.*) as num
FROM goods as g
LEFT JOIN evaluation as e on e.goods_id=g.id
HAVING COUNT(e.*)> GROUP BY g.id

这样就不行了,查询不到了。
这时候就需要使用LATERAL

SELECT
g.*,
e.num
FROM goods as g
LEFT JOIN LATERAL(
SELECT COUNT(ev.id) as num FROM evaluation AS ev
WHERE ev.goods_id=g.id
) AS e ON TRUE
WHERE = AND num>

3、然后我们再次查询这些商品的信息,希望找到黄金会员评论的商品信息
这时候LATERAL的优势就更加明显了

SELECT
g.*,
e.num
FROM goods as g
LEFT JOIN LATERAL(
SELECT COUNT(ev.id) as num
FROM evaluation AS ev
LEFT JOIN users u on u.id=ev.user_id
WHERE ev.goods_id=g.id AND u.grade=
) AS e ON TRUE
WHERE = AND num>

什么是LATERAL

我们先来看官方对lateral的定义

可以在出现于FROM中的子查询前放置关键词LATERAL。这允许它们引用前面的FROM项提供的列(如果没有 LATERAL,每一个子查询将被独立计算,并且因此不能被其他FROM项交叉引用)。
出现在FROM中的表函数的前面也可以被放上关键词LATERAL,但对于关键词的不可选的,在任何情况下函 数的参数都可以包含前面FROM项提供额列的引用。
一个LATERAL项可以出现在FROM列表项层,或者出现在一个JOIN树中。在后者如果出现在JOIN的右部, 那么可以引用在JOIN左部分的任何项。
如果一个FROM项包含LATERAL交叉引用,计算过程中:对于提供交叉引用列的FROM项的每一行,或者 多个提供这些列的多个FROM项进行集合,LATERAL项将被使用该行或者行集中的列值进行计算。得到结 果行将和它们被计算出来的行进行正常的连接。对于来自这些列的源表的每一行或行集,该过程将重复。

手册上提到:

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

在 LATERAL (这里可以关联(引用)lateral左边的表或子句)  

所以允许:   

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

带有LATERAL的SQL的计算步骤

1、逐行提取被lateral子句关联(引用)的FROM或JOIN的ITEM(也叫source table)的记录(s) 中的column(s)

for each row of the FROM item providing the cross-referenced column(s),
or set of rows of multiple FROM items providing the columns,

2、使用以上提取的columns(s),关联计算lateral子句中的ITEM
the LATERAL item is evaluated using that row or row set'us values of the columns.

3、lateral的计算结果row(s),与所有from,join ITEM(S)正常的进行join计算 The resulting row(s) are joined as usual with the rows they were computed from.

4、从1到3开始循环,直到所有的source table的行取尽。
This is repeated for each row or set of rows from the column source table(s).

LATERAL在OUTER JOIN中的使用限制(或定义限制)

由于lateral的计算步骤是从source table逐条展开的,所以OUTER JOIN时只能使用source table 作为whole端,LATERAL内的ITEM不能作为WHOLE端。
因此lateral只能在left join的右边。或者right join的左边。因此不能是WHOLE端。

The column source table(s) must be INNER or LEFT joined to the LATERAL item,   

else there would not be a well-defined set of rows from which to compute each set of rows for the LATERAL item.   

Thus, although a construct such as X RIGHT JOIN LATERAL Y is syntactically valid,   

it is not actually allowed for Y to reference X.  

LATERAL的几个简单的例子

1、
A trivial example of LATERAL is

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

This is not especially useful since it has exactly the same result as the more conventional

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

一个LATERAL项可以出现在FROM列表项层
2、
LATERAL is primarily useful when the cross-referenced column is necessary for computing the row(s) to be joined. A common application is providing an argument value for a set-returning function. For example, supposing that vertices(polygon) returns the set of vertices of a polygon, we could identify close-together vertices of polygons stored in a table with:

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) < AND p1.id != p2.id;

This query could also be written

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) < AND p1.id != p2.id;

函数调用,支持应用函数左边的ITEM(S)。所以可以看消除LATERAL,语义是一样的。
(As already mentioned, the LATERAL key word is unnecessary in this example, but we use it for clarity.)

3、
It is often particularly handy to LEFT JOIN to a LATERAL subquery, so that source rows will appear in the result even if the LATERAL subquery produces no rows for them. For example, if get_product_names() returns the names of products made by a manufacturer, but some manufacturers in our table currently produce no products, we could find out which ones those are like this:

SELECT m.name
FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true
WHERE pname IS NULL;

lateral的查询结果也是可以作为整个语句的查询条件的

总结

1、lateral 可以出现在FROM的列表项层,也可以出现在JOIN数树中,如果出现在JOIN的右部分,那么 可以引用在JOIN左部分的任何项。
2、由于lateral的计算步骤是从source table逐条展开的,所以OUTER JOIN时只能使用source table 作为whole端,LATERAL内的ITEM不能作为WHOLE端。
3、LATERAL 关键词可以在前缀一个 SELECT FROM 子项. 这能让 SELECT 子项在FROM项出现之前就引 用到FROM项中的列. (没有 LATERAL 的话, 每一个 SELECT 子项彼此都是独立的,因此不能够对其 它的 FROM 项进行交叉引用.)
4、当一个 FROM 项包含 LATERAL 交叉引用的时候,查询的计算过程如下: 对于FROM项提供给交叉引 用列的每一行,或者多个FROM像提供给引用列的行的集合, LATERAL 项都会使用行或者行的集合的列 值来进行计算. 计算出来的结果集像往常一样被加入到联合查询之中. 这一过程会在列的来源表的行或 者行的集合上重复进行.

参考

【PostgreSQL 9.3 add LATERAL support - LATERAL的语法和用法介绍】https://github.com/digoal/blog/blob/master/201210/20121008_01.md?spm=a2c4e.10696291.0.0.408619a4cXorB6&file=20121008_01.md
【LATERAL】https://www.postgresql.org/docs/devel/queries-table-expressions.html#QUERIES-LATERAL

pgsql中的lateral使用小结的更多相关文章

  1. Delphi中ClientDataSet的用法小结

    Delphi中ClientDataSet的用法小结 TClientDataSet控件继承自TDataSet,其数据存储文件格式扩展名为 .cds,是基于文件型数据存储和操作的控件.该控件封装了对数据进 ...

  2. EntityFramework中几种操作小结

    目前项目中使用到的EntityFramework中几种操作小结,先标记下.没有详细介绍,后续有空的话再补充一些并完善一下. 列中加入RowVersion时间戳 public class Product ...

  3. 关于 C# 中接口的一些小结

    < 关于 C# 中“接口”的一些小结 > 对于 C# 这样的不支持多重继承的语言,很好的体现的层次性,但是有些时候多重继承的确有一些用武之地.   比如,在 Stream 类 . 图形设备 ...

  4. hive中的lateral view 与 explode函数的使用

    hive中的lateral view 与 explode函数的使用 背景介绍: explode与lateral view在关系型数据库中本身是不该出现的. 因为他的出现本身就是在操作不满足第一范式的数 ...

  5. C#中SqlDataAdapter的使用小结---转载

    C#中SqlDataAdapter的使用小结 转载 叁木-Neil 最后发布于2018-06-07 21:29:39 阅读数 8275 收藏 展开 SqlDataAdapter对象 一.特点介绍1.表 ...

  6. pgsql中的行锁

    pgsql中的行锁 前言 用户可见的锁 regular Lock 行级别 FOR UPDATE FOR NO KEY UPDATE FOR SHARE FOR KEY SHARE 测试下加锁之后的数据 ...

  7. pgsql中的事务隔离

    pgsql中的事务隔离级别 前言 事物隔离级别 在各个级别上被禁止出现的现象是 脏读 不可重复读 幻读 序列化异常 读已提交隔离级别 可重复读隔离级别 可序列化隔离级别 摘录 pgsql中的事务隔离级 ...

  8. windows中抓取hash小结(下)

    书接上回,windows中抓取hash小结(上) 指路链接 https://www.cnblogs.com/lcxblogs/p/13957899.html 继续 0x03 从ntds.dit中抓取 ...

  9. windows中抓取hash小结(上)

    我上篇随笔说到了内网中横向移动的几种姿势,横向移动的前提是获取了具有某些权限的用户的明文密码或hash,正愁不知道写点啥,那就来整理一下这个"前提"-----如何在windows系 ...

随机推荐

  1. Html网页链接数据库验证账户密码(新手)

    连接代码(其中用到了连接池,不要忘记Jar包.拉入配置文件和工具类): package cn.Wuchuang.Servlet; import org.springframework.jdbc.cor ...

  2. C++之 ostream详细用法

    前言 在 C++中,ostream表示输出流,英文”output stream“的简称.在 C++中常见的输出流对象就是标准输出流cout,很少自定义ostream的对象,更多的是直接使用cout.那 ...

  3. Css五种定位之间的区别

    ##CSS 定位机制## CSS 有三种基本的定位机制:普通流.浮动流和定位流. 除非专门指定,否则所有框都在普通流中定位.也就是说,普通流中的元素的位置由元素在 (X)HTML 中的位置决定. 块级 ...

  4. Vue-Cli4笔记

    Vue-Cli4与Vue-Cli2区别浅谈 当时学习 Vue-Cli 的时候看的是 Vue-Cli2 的相关教程,当把 package.json 上传 github 的时候提醒有安全问题,于是准备使用 ...

  5. 2020kali浏览器汉化等配置

    0.修改搜索引擎 1. 2. 3.点击左侧搜索,输入language因为我已经修改为中文所以没有查询到结果 4点击搜索更多语言(未汉化未英文)找到chinese后添加 5.要将chinese上移到第一 ...

  6. hdu1035 机器人走格子,格子指明方向,问几步走出格子或者是否有形成圈

    只要根据格子的方向选择下一步搜索的方向即可,退出条件是出界或者进入环中,进入环中的条件也很好确定,就是一个点走了两次,由于路径是固定的,这就会陷入无限循环. #include<iostream& ...

  7. centos 安装activeMq

    Apache ActiveMQ是一个免费的开源消息代理和集成模式服务器.它支持来自JAVA.c++.C.Python.Perl.PHP等多种语言的客户端和协议.它提供了许多功能,如消息组.虚拟目的地. ...

  8. 2019牛客多校第四场 A meeting

    链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...

  9. SpringBoot 整合 MyCat 实现读写分离

    MyCat一个彻底开源的,面向企业应用开发的大数据库集群.基于阿里开源的Cobar产品而研发.能满足数据库数据大量存储:提高了查询性能.文章介绍如何实现MyCat连接MySQL实现主从分离,并集成Sp ...

  10. JSON字符串带BOM头"ufeff"

    调用三方接口返回值JSON字符串带BOM头"\ufeff",JSON解析死活报错. 我是用SpringBoot的RestTemplate调用三方接口的,一开始返回值我是用对象接收返 ...