pgsql中的lateral使用小结
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使用小结的更多相关文章
- Delphi中ClientDataSet的用法小结
Delphi中ClientDataSet的用法小结 TClientDataSet控件继承自TDataSet,其数据存储文件格式扩展名为 .cds,是基于文件型数据存储和操作的控件.该控件封装了对数据进 ...
- EntityFramework中几种操作小结
目前项目中使用到的EntityFramework中几种操作小结,先标记下.没有详细介绍,后续有空的话再补充一些并完善一下. 列中加入RowVersion时间戳 public class Product ...
- 关于 C# 中接口的一些小结
< 关于 C# 中“接口”的一些小结 > 对于 C# 这样的不支持多重继承的语言,很好的体现的层次性,但是有些时候多重继承的确有一些用武之地. 比如,在 Stream 类 . 图形设备 ...
- hive中的lateral view 与 explode函数的使用
hive中的lateral view 与 explode函数的使用 背景介绍: explode与lateral view在关系型数据库中本身是不该出现的. 因为他的出现本身就是在操作不满足第一范式的数 ...
- C#中SqlDataAdapter的使用小结---转载
C#中SqlDataAdapter的使用小结 转载 叁木-Neil 最后发布于2018-06-07 21:29:39 阅读数 8275 收藏 展开 SqlDataAdapter对象 一.特点介绍1.表 ...
- pgsql中的行锁
pgsql中的行锁 前言 用户可见的锁 regular Lock 行级别 FOR UPDATE FOR NO KEY UPDATE FOR SHARE FOR KEY SHARE 测试下加锁之后的数据 ...
- pgsql中的事务隔离
pgsql中的事务隔离级别 前言 事物隔离级别 在各个级别上被禁止出现的现象是 脏读 不可重复读 幻读 序列化异常 读已提交隔离级别 可重复读隔离级别 可序列化隔离级别 摘录 pgsql中的事务隔离级 ...
- windows中抓取hash小结(下)
书接上回,windows中抓取hash小结(上) 指路链接 https://www.cnblogs.com/lcxblogs/p/13957899.html 继续 0x03 从ntds.dit中抓取 ...
- windows中抓取hash小结(上)
我上篇随笔说到了内网中横向移动的几种姿势,横向移动的前提是获取了具有某些权限的用户的明文密码或hash,正愁不知道写点啥,那就来整理一下这个"前提"-----如何在windows系 ...
随机推荐
- 通过极简模拟框架让你了解ASP.NET Core MVC框架的设计与实现[上篇]
<200行代码,7个对象--让你了解ASP.NET Core框架的本质>让很多读者对ASP.NET Core管道有了真实的了解.在过去很长一段时间中,有很多人私信给我:能否按照相同的方式分 ...
- 《Python学习手册 第五版》 -第16章 函数基础
前面的章节讲解的是一些基础数据类型.基本语句使用和一些文档查看的内容,这些都是一些基础,其实还谈不上入门,只有了解了函数,才算入门 函数是编程里面使用最多的也是最基本的程序结构, 本章重点内容 1.函 ...
- angular6 增加webpack配置 亲测可用
核心 Angular Cli 6 禁用了webpack的自定义配置,官方似乎并未提供自定义配置webpack的方法. 在此之前,可以使用ng eject把默认的webpack提取到代码中,进行自定义. ...
- Django之Cookie,Session
COOKIE Cookie的由来 大家都知道HTTP协议是无状态的. 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不 ...
- select_related prefetch_related
# select_related与prefetch_related# # select_related帮你直接连表操作 查询数据 括号内只能放外键字段# # res = models.Book.obj ...
- laravel的中间件创建思路
网上有很多解析laravel中间件的实现原理,但是不知道有没有读者在读的时候不明白,作者是怎么想到要用array_reduce函数的? 本文从自己的角度出发,模拟了如果我是作者,我是怎么实现这个中间件 ...
- webpack打包es6代码
1.简单描述一下es6的模块导入和导出的语法: //导出:export var aa = 10;export function demo(){} //不能写成:var aa = 10;export a ...
- JDBC(四)----数据库连接池
## 数据库连接池 * 概念:其实就是一个容器(集合) * 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后会将连接对象归还给容 ...
- CodeForces 196B Infinite Maze
Infinite Maze time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- 关于Anaconda安装以后使用Jupyter Notebook无法直接打开浏览器的解决方法
关于Anaconda安装以后使用Jupyter Notebook无法直接打开浏览器的解决方法 1.首先打开Anoconda Prompt,输入命令 jupyter notebook --generat ...