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. Linux学习第六天

    学习Linux环境下的挂载命令. 什么是挂载命令? 1.Windows下,mount挂载,就是给磁盘分区提供一个盘符(C,D,E,...).比如插入U盘后系统自动分配给了它I:盘符其实就是挂载,退优盘 ...

  2. 华为云+NextCloud(私人云盘搭建)

    这几天发现了牛客+华为云的返现活动,免费用一年,赶紧的去搞了一个折腾折腾.(相关软件下载链接在最下面) 噔噔噔!!! 102822985.png) 废话少说,开始搭建. 基础环境部署 Apache安装 ...

  3. Nginx双机主备(Keepalived实现)

    前言 首先介绍一下Keepalived,它是一个高性能的服务器高可用或热备解决方案,起初是专为LVS负载均衡软件设计的,Keepalived主要来防止服务器单点故障的发生问题,可以通过其与Nginx的 ...

  4. session生命周期,与cookie的区别

    sessinon在用户访问第一次访问服务器时创建. Session什么时候失效? 1. 服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效.Tomcat中Sessio ...

  5. 1、Spark Core所处位置和主要职责

    Spark组件是基于分布式资源引擎层(Yarn等)和分布式存储层(HDFS等)之上的一个组件,Spark本质上是一个计算引擎,负责计算的,根据不同计算场景划分出了SQL.Streaming.MLib. ...

  6. 面试刷题22:CAS和AQS是什么?

    java并发包提供的同步工具和线程池,底层是基于什么原理来设计和实现的呢?这个非常重要. 我是李福春,我在准备面试,今天的题目是: CAS和AQS是什么? 答:CAS是一系列的操作集合,获取当前值进行 ...

  7. NOI ONLINE 提高组 序列 根据性质建图

    题目链接 https://www.luogu.com.cn/problem/P6185 题意 应该不难懂,跳过 分析 说实话第一眼看到这题的时候我有点懵,真不知道怎么做,不过一看数据,还好还好,暴力能 ...

  8. Samba centos7文件共享服务器搭建教程,可以更改任意需求操作配置详解。

    先安装软件   yum -y install samba-client 请看如下配置文件说明 [gongxiang]       comment = This is my shared folder  ...

  9. adb的基本安装和介绍(一)

    一,什么是adb? adb全称为Android Debug Bridge,就是起到调试桥的作用.顾名思义,adb就是android sdk 的一个工具 借助adb工具,我们可以管理设备或手机模拟器的状 ...

  10. Springmvc与Struts区别?

    在一个技术群里看到机器人解释的二者区别,在此Mark下. 一.框架机制 spring mvc 和 struts2的加载机制不同:spring mvc的入口是servlet,而struts2是filte ...