Postgres:左连接,order by和limit 1
Posted
技术标签:
【中文标题】Postgres:左连接,order by和limit 1【英文标题】:Postgres: left join with order by and limit 1 【发布时间】:2014-03-17 06:01:52 【问题描述】:我有这种情况:
Table1 has a list of companies.
Table2 has a list of addresses.
Table3 is a N relationship of Table1 and Table2, with fields 'begin' and 'end'.
由于公司可能会随着时间的推移而移动,因此它们之间的 LEFT JOIN 会导致每个公司有多个记录。
begin
和 end
字段永远不会为 NULL。找到最新地址的解决方案是使用ORDER BY being DESC
,删除旧地址是LIMIT 1
。
如果查询只能带来 1 家公司,那就可以了。但我需要一个将所有 Table1 记录与它们当前的 Table2 地址连接起来的查询。因此,必须在 LEFT JOIN 的 ON 子句中删除过时数据(AFAIK)。
知道如何建立条款以不创建重复的 Table1 公司并带来最新地址吗?
【问题讨论】:
【参考方案1】:在连接条件中使用带有 max() 函数的依赖子查询。 类似这个例子:
SELECT *
FROM companies c
LEFT JOIN relationship r
ON c.company_id = r.company_id
AND r."begin" = (
SELECT max("begin")
FROM relationship r1
WHERE c.company_id = r1.company_id
)
INNER JOIN addresses a
ON a.address_id = r.address_id
演示:http://sqlfiddle.com/#!15/f80c6/2
【讨论】:
在 sqlfiddle 上很好 - 我直到现在才看到 jsfiddle,但 sqlfiddle 似乎超级有用! 如果 r.begin 在某些记录中可以相等,它似乎不起作用【参考方案2】:我设法使用 Windows 功能解决了它:
WITH ranked_relationship AS(
SELECT
*
,row_number() OVER (PARTITION BY fk_company ORDER BY dt_start DESC) as dt_last_addr
FROM relationship
)
SELECT
company.*
address.*,
dt_last_addr as dt_relationship
FROM
company
LEFT JOIN ranked_relationship as relationship
ON relationship.fk_company = company.pk_company AND dt_last_addr = 1
LEFT JOIN address ON address.pk_address = relationship.fk_address
row_number() 在基于 fk_company 的每个窗口内为每个记录创建一个 int 计数器。对于每个窗口,日期最新的记录排在第一位,排名为 1,然后dt_last_addr = 1
确保每个fk_company
只发生一次 JOIN,地址最新的记录。
窗口函数非常强大,很少有人使用它们,它们避免了许多复杂的连接和子查询!
【讨论】:
【参考方案3】:从 PostgreSQL 9.3 开始,JOIN LATERAL
(https://www.postgresql.org/docs/9.4/queries-table-expressions.html) 允许进行子查询加入,因此它以优雅的方式解决了您的问题:
SELECT * FROM companies c
JOIN LATERAL (
SELECT * FROM relationship r
WHERE c.company_id = r.company_id
ORDER BY r."begin" DESC LIMIT 1
) r ON TRUE
JOIN addresses a ON a.address_id = r.address_id
这种方法的缺点是LATERAL
里面的表的索引在外面不起作用。
【讨论】:
您能否详细说明您的评论“这种方法的缺点是 LATERAL 内部表的索引在外部不起作用。”在您的示例中,如果r.company_id
上有索引,这是否意味着索引 将 用于子查询,但如果在外部查询中的 WHERE 子句?
@EricDauenhauer 是的,确实如此。以上是关于Postgres:左连接,order by和limit 1的主要内容,如果未能解决你的问题,请参考以下文章
使用具有不同 order by 子句的 postgres 窗口函数
ORDER BY 中的最后一个案例执行不正确 postgres
使用 LIMIT / ORDER BY 和 pg Postgres NodeJS 作为参数