SQL中同一表的“插值上一个值”

SQL中同一表的“插值上一个值”,sql,join,interpolation,vertica,Sql,Join,Interpolation,Vertica,我遇到了一个问题,我需要做一些事情,作为连接中的插值前一个值,但不是从我连接的表,而是从原始表。让我解释一下: Table A: Item Package Start_date Finish_date X 12345 2020-01-01 2020-02-01 X 6789 2020-02-02 2020-03-02 Table B Item Date X 2020-01-15 X 2020-02-15 X 2020-03-15

我遇到了一个问题,我需要做一些事情,作为连接中的插值前一个值,但不是从我连接的表,而是从原始表。让我解释一下:

Table A:

Item Package Start_date Finish_date
 X   12345   2020-01-01 2020-02-01
 X   6789    2020-02-02 2020-03-02


Table B

Item   Date     
 X   2020-01-15 
 X   2020-02-15
 X   2020-03-15
我想知道,在表B的日期,表A中的哪个包裹是我的物品。因此,我:

select Item, Date, Package 
from B
left join A on (B.Item = A.Item and B.Date between StartDate and FinishDate)
我得到:

Item  Date      Package
X   2020-01-15  12345
X   2020-02-15  6789
X   2020-03-15  NULL
但我希望看到的不是null,而是Package的最后一个非空值event,如果日期超出了这里的日期范围,它将是6789

有人知道怎么做吗?

使用两个连接。一个用于匹配,一个用于默认:

select b.Item, b.Date, 
       coalesce(a.Package, adef.Package) as Package 
from B left join
     A
     on B.Item = A.Item and
        B.Date between A.StartDate and A.FinishDate left join
     (select a.*,
             row_number() over (partition by item order by StartDate desc) as seqnum
      from a
     ) adef
     on adef.item = B.item and
        adef.seqnum = 1 and
        a.item is null;
编辑:

实际上,您可以将其合并为一个联接:


尽管您可以在此处轻松地使用带有插值前一个值的左连接,但可能存在需要精确的复杂连接谓词的数据星座,其中使用的谓词组合了equi和BETWEEN

如果你需要的话,我想不出你会在我脑海中出现的情况,那么请帮助我,这将是一个简单的OLAP,Window,Vertica中可用的函数:LAST_VALUE IGNORE NULLS,它返回OLAP窗口中的最后一个非null值

但我怀疑您是否需要它,所以我在下面添加了这两种解决方案

在包含两个常用表表达式的初始WITH子句中重复输入,使用join时,应如下所示:

WITH
a(item,package,start_date,finish_date) as (
          SELECT 'X',12345,DATE '2020-01-01',DATE '2020-02-01'
UNION ALL SELECT 'X',6789,DATE '2020-02-02',DATE '2020-03-02'
)
,
b(item,date) AS (
          SELECT 'X',DATE '2020-01-15'
UNION ALL SELECT 'X',DATE '2020-02-15'
UNION ALL SELECT 'X',DATE '2020-03-15'
)
SELECT
  b.item
, b.date
, LAST_VALUE(a.package IGNORE NULLS) OVER(w) AS package
FROM b
LEFT JOIN a 
 ON a.item=b.item
AND b.date BETWEEN start_date AND finish_date
WINDOW w AS(PARTITION BY b.item ORDER BY b.date)
ORDER BY 2;
-- out  item |    date    | package 
-- out ------+------------+---------
-- out  X    | 2020-01-15 |   12345
-- out  X    | 2020-02-15 |    6789
-- out  X    | 2020-03-15 |    6789
不过,插值前一个值左连接谓词也适用于此数据星座,如下所示

WITH
a(item,package,start_date,finish_date) as (
          SELECT 'X',12345,DATE '2020-01-01',DATE '2020-02-01'
UNION ALL SELECT 'X',6789,DATE '2020-02-02',DATE '2020-03-02'
)
,
b(item,date) AS (
          SELECT 'X',DATE '2020-01-15'
UNION ALL SELECT 'X',DATE '2020-02-15'
UNION ALL SELECT 'X',DATE '2020-03-15'
)
SELECT
  b.item
, b.date
, a.package
FROM b
LEFT JOIN a 
 ON a.item=b.item
AND b.date INTERPOLATE PREVIOUS VALUE start_date
ORDER BY 2;
-- out  item |    date    | package 
-- out ------+------------+---------
-- out  X    | 2020-01-15 |   12345
-- out  X    | 2020-02-15 |    6789
-- out  X    | 2020-03-15 |    6789
值得一试的是哪一个更快-范围连接谓词或插值前一个值谓词

值得检查哪一个版本更快-而且你并不总是处于有一个完成日期的舒适状态


你能试一下这两种方法吗?告诉我们哪一种更快?

用你正在使用的数据库标记你的问题。顺便说一下,你所做的是外推而不是插值。你能解释一下为什么在B.Date>A.FinishDate和seqnum-1中有seqnum-1吗?没有它会发生什么变化?如果B中只有X项的一个日期,并且它超出了A的所有日期间隔,它将如何变化?但我仍然需要得到最后一个包装,因为它是一个打字错误。2这些查询就是这样做的。
WITH
a(item,package,start_date,finish_date) as (
          SELECT 'X',12345,DATE '2020-01-01',DATE '2020-02-01'
UNION ALL SELECT 'X',6789,DATE '2020-02-02',DATE '2020-03-02'
)
,
b(item,date) AS (
          SELECT 'X',DATE '2020-01-15'
UNION ALL SELECT 'X',DATE '2020-02-15'
UNION ALL SELECT 'X',DATE '2020-03-15'
)
SELECT
  b.item
, b.date
, a.package
FROM b
LEFT JOIN a 
 ON a.item=b.item
AND b.date INTERPOLATE PREVIOUS VALUE start_date
ORDER BY 2;
-- out  item |    date    | package 
-- out ------+------------+---------
-- out  X    | 2020-01-15 |   12345
-- out  X    | 2020-02-15 |    6789
-- out  X    | 2020-03-15 |    6789