摆脱 JOIN LATERAL
Get rid of a JOIN LATERAL
我有两个这样的表:
CREATE TABLE log
(program int, time int, a int, b int)
;
INSERT INTO log
(program, time, a, b)
VALUES
(1, 5, 3, 4),
(1, 10, 5, 6),
(2, 5, 7, 8)
;
CREATE TABLE params
(program int, time int, a_ref int, b_ref int)
;
INSERT INTO params
(program, time, a_ref,b_ref)
VALUES
(1, 3, 4, 5),
(1, 4, 6, 7),
(2, 6, 8, 9)
;
对于log
中的每个条目我可以在params
中找到对应的条目(想象一下:program
的参考参数),并且给定一个log
,我需要找到具有相同 program
且时间戳小于 log
时间戳的最新条目。
一个有效的查询是这样的:
SELECT log.a, log.b, params.a_ref, params.b_ref
FROM log
LEFT JOIN LATERAL (
select *
from params
where params.time < log.time
and params.program = log.program
ORDER BY time
DESC LIMIT 1
) params ON log.program = params.program
当我理解正确时,我不得不将嵌套查询 (SELECT .. ORDER BY)
想象成对 log
中的每一行执行的查询。
有机会摆脱它吗?
摆脱横向连接的一种方法是在派生的 table 中使用 distinct on ()
并将时间列的限制添加到连接条件中:
SELECT log.a, log.b, params.a_ref, params.b_ref
FROM log
LEFT JOIN (
select distinct on (program) *
from params
order by program, time desc
) params ON log.program = params.program
and params.time < log.time
SQL-标准解:
- 加入
log
所有可能的params
- 对于每个可能的
params
计算其与 log.time
的距离的顺序(并对超出范围的最后一个值进行排序)
- 排名第 1 的行是您想要的结果
select a, b, a_ref, b_ref
from (
select log.a, log.b
, case when log.time > params.time then params.a_ref else null end as a_ref
, case when log.time > params.time then params.b_ref else null end as b_ref
, row_number() over (partition by log.a, log.b, log.program order by log.time <= params.time, log.time - params.time) as rn
from log
join params on log.program = params.program
) x
where rn = 1
我有两个这样的表:
CREATE TABLE log
(program int, time int, a int, b int)
;
INSERT INTO log
(program, time, a, b)
VALUES
(1, 5, 3, 4),
(1, 10, 5, 6),
(2, 5, 7, 8)
;
CREATE TABLE params
(program int, time int, a_ref int, b_ref int)
;
INSERT INTO params
(program, time, a_ref,b_ref)
VALUES
(1, 3, 4, 5),
(1, 4, 6, 7),
(2, 6, 8, 9)
;
对于log
中的每个条目我可以在params
中找到对应的条目(想象一下:program
的参考参数),并且给定一个log
,我需要找到具有相同 program
且时间戳小于 log
时间戳的最新条目。
一个有效的查询是这样的:
SELECT log.a, log.b, params.a_ref, params.b_ref
FROM log
LEFT JOIN LATERAL (
select *
from params
where params.time < log.time
and params.program = log.program
ORDER BY time
DESC LIMIT 1
) params ON log.program = params.program
当我理解正确时,我不得不将嵌套查询 (SELECT .. ORDER BY)
想象成对 log
中的每一行执行的查询。
有机会摆脱它吗?
摆脱横向连接的一种方法是在派生的 table 中使用 distinct on ()
并将时间列的限制添加到连接条件中:
SELECT log.a, log.b, params.a_ref, params.b_ref
FROM log
LEFT JOIN (
select distinct on (program) *
from params
order by program, time desc
) params ON log.program = params.program
and params.time < log.time
SQL-标准解:
- 加入
log
所有可能的params
- 对于每个可能的
params
计算其与log.time
的距离的顺序(并对超出范围的最后一个值进行排序) - 排名第 1 的行是您想要的结果
select a, b, a_ref, b_ref
from (
select log.a, log.b
, case when log.time > params.time then params.a_ref else null end as a_ref
, case when log.time > params.time then params.b_ref else null end as b_ref
, row_number() over (partition by log.a, log.b, log.program order by log.time <= params.time, log.time - params.time) as rn
from log
join params on log.program = params.program
) x
where rn = 1