摆脱 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

SQL fiddle

当我理解正确时,我不得不将嵌套查询 (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

Online example

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

Fiddle here.