使用插值将日期转换为联接中的时间戳

问题描述 投票:0回答:3

我在 Vertica 中有一张表

a
,其中包含
item_id
附加到
code
的时间
from_date

create table a (
    code      varchar(16),
    item_id   int,
    from_date timestamptz
);

和一个表格

b
,其中包含给定日期的
code
t

create table b (
    code    varchar(16),
    t       date
);

我需要在

a.item_id
日期从
b.code
检索
b.t
。数据看起来像这样:

insert into a values ('abc', 1, '2013-01-01 10:00:00 EST'::timestamptz);
insert into a values ('abc', 2, '2013-01-05 11:00:00 EST'::timestamptz);
insert into a values ('abc', 3, '2013-01-09 9:00:00 EST'::timestamptz);

insert into b values ('abc', '2013-01-06'::date);

我尝试在 LEFT JOIN 中使用 Vertica 的 INTERPOLATE,以便在

(code, item_id)
时检索前一个
t

select
    b.code, b.t, a.item_id
from  b
left join a on a.code = b.code and b.t INTERPOLATE PREVIOUS VALUE a.t;

这给了我一个类型错误

Interpolated predicates can accept arguments of the same type only

所以我尝试将

b.t
转换为时间戳

select
    b.code, b.t, a.item_id
from b
left join a on a.code = b.code
    and (b.t::timestamptz) INTERPOLATE PREVIOUS VALUE a.t;

这给了我一个语法错误

Syntax error at or near "INTERPOLATE"

如果没有 INTERPOLATE,SQL 表达式可以工作,但不会连接上一行。

是否可以在 JOIN 和 INTERPOLATE 中将我的日期转换为时间戳?

如果没有,是否有其他方法可以让我在时间

item_id
检索当前的
t

sql timestamp vertica
3个回答
1
投票

我发现了一个巧妙的解决方法,通过欺骗解释器并在 SELECT 子查询中进行日期到时间戳的转换:

select
    b.code, b.t, a.item_id
from b
left join (select a.t::date, a.code, a.item from a) a on a.code = b.code
    and b.t INTERPOLATE PREVIOUS VALUE a.t;

0
投票
select b.code, b.t, a.item_id
from b
left join a on a.code = b.code and b.t = cast(a.t as date);

但是,当“a”表中有超过 1 行,其中 t 包含同一日期的不同时间时,此解决方案可能是错误的。

例如,

insert into a values ('abc', 4, '2013-01-06 8:00:00 EST'::timestamptz);
insert into a values ('abc', 5, '2013-01-06 9:00:00 EST'::timestamptz);

在这种情况下,您应该决定需要哪一行。 比如说,您需要最新行:

select b.code, b.t, a.item_id
from b
left join (
    select a1.code, a1.item_id, a2.dt
    from a a1
    inner join (
        select code, cast(t as date) dt, max(t) as max_t
        from a
        group by code, cast(t as date)
    ) a2 on a1.code = a2.code and a1.t = a2.max_t
) a on a.code = b.code and b.t = a.dt;

解决方案可能会有所不同,具体取决于您的 DBMS。


0
投票

虽然

INTERPOLATE
不支持强制转换和表达式,但允许使用子查询,并且可以使用子查询将
DATE
强制转换为
TIMESTAMPTZ
。然而,这种简单的方法似乎行不通,经过一番尝试,我得到了以下要求:

WITH
b_ext AS (
    SELECT
        code,
        t,  -- This is a DATE
        t::TIMESTAMPTZ + '0 S'::INTERVAL AS dt
    FROM b
)
SELECT
    b.code, b.t, a.item_id
FROM
    b_ext b
    LEFT JOIN a
    ON a.code = b.code AND b.dt INTERPOLATE PREVIOUS VALUE a.t;

不知何故,转换

t::TIMESTAMPTZ
还不够,确实需要添加零
INTERVAL
,至少在Vertica 11.0中是这样。

© www.soinside.com 2019 - 2024. All rights reserved.