按最近的时间加入 2 个表,PostgreSQL 9.6

del*_*kov 6 postgresql join time

我有 2 个表:tbl1、tbl2。

CREATE TABLE tbl1(time_1)
AS VALUES
  ( '2017-09-06 15:26:03'::timestamp ),
  ( '2017-09-06 15:26:02' ),
  ( '2017-09-06 15:28:01' ),
  ( '2017-09-06 15:40:00' );

CREATE TABLE tbl2(time_2)
AS VALUES
  ( '2017-09-06 15:29:01'::timestamp ),
  ( '2017-09-06 15:40:00' ),
  ( '2017-09-06 15:23:59' ),
  ( '2017-09-06 15:45:58' );
Run Code Online (Sandbox Code Playgroud)

我想加入表格,因此对于 tbl1 中的每一行都匹配 tbl2 中最接近的时间。输出是:

     time_1                     time_2
---------------------      --------------------
 2017-09-06 15:26:03      2017-09-06 15:23:59      
 2017-09-06 15:26:02      2017-09-06 15:23:59 
 2017-09-06 15:28:01      2017-09-06 15:29:01
 2017-09-06 15:40:00      2017-09-06 15:45:58
Run Code Online (Sandbox Code Playgroud)

我知道如何找到最近时间的单个值:

SELECT * from tbl1 where time_1=INPUT_TIME ORDER BY case when time_1 > INPUT_TIME then time_1 - INPUT_TIME else INPUT_TIME - time_1 end limit 1;
Run Code Online (Sandbox Code Playgroud)

Eva*_*oll 7

使用btree_gist<->

您真的希望<->通过内部tstz_dist. 这是有效的,因为您并不真正关心间隔。首先你需要添加扩展名,

CREATE EXTENSION btree_gist;
Run Code Online (Sandbox Code Playgroud)

然后

SELECT DISTINCT ON (time_1) time_1, time_2
FROM tbl1
CROSS JOIN tbl2
ORDER BY time_1, time_1 <-> time_2;
Run Code Online (Sandbox Code Playgroud)

如果要进行交叉连接的行太多,则横向解决方案可能会更好。

SELECT time_1, time_2
FROM tbl1
CROSS JOIN LATERAL (
  SELECT time_2
  FROM tbl2
  ORDER BY time_1<->time_2
  LIMIT 1
) AS tbl2;
Run Code Online (Sandbox Code Playgroud)

有兴趣看到有关基准的报告。=) 特别是如果您在 time_1 和 time_2 上有 GIST 索引。

  • 我遵循了你的第二种方法,效果非常好!将我的特定查询从 45 秒减少到大约 2 秒 (2认同)

Len*_*art 2

这是使用横向连接的一种尝试:

select time_1, time_2
from tbl1 
cross join lateral (
    select time_2 
    from tbl2 
    order by case when time_1 > time_2 then age(time_1,time_2) 
                                       else age(time_2,time_1) 
             end 
    fetch first 1 rows only
) as t;
Run Code Online (Sandbox Code Playgroud)

另一种可能性是使用子查询:

select time_1, (
    select time_2 
    from tbl2 
    order by case when time_1 > time_2 then age(time_1,time_2) 
                                       else age(time_2,time_1) 
             end 
    fetch first 1 rows only
)
from tbl1;
Run Code Online (Sandbox Code Playgroud)

可能有一种更优雅的方法来确定时间戳差的绝对值。值得注意的是,如果改变表的顺序,结果将会不同。