另一个日期差距填补SQL拼图

时间:2011-12-27 02:20:55

标签: sql date fill vertica gaps-in-data

我正在使用Vertica,这让我无法使用CROSS APPLY。显然,Vertica中没有CTE这样的东西。

这就是我所拥有的:

t:
    day    | id | metric | d_metric
-----------+----+--------+----------
2011-12-01 |  1 | 10     | 10
2011-12-03 |  1 | 12     | 2
2011-12-04 |  1 | 15     | 3

请注意,在第一天,delta等于指标值。 我想填补空白,如下:

t_fill:
    day    | id | metric | d_metric
-----------+----+--------+----------
2011-12-01 |  1 | 10     | 10
2011-12-02 |  1 | 10     | 0 -- a delta of 0
2011-12-03 |  1 | 12     | 2
2011-12-04 |  1 | 15     | 3

我想到了一种日复一日的方法,但我真正喜欢的是一种可以一次性运行的解决方案。

我认为我可以使用LAST_VALUE,但我无法提出正确的JOIN语句,这些语句可以让我对每个id的日常历史进行正确的分区和排序。

编辑: 假设我有一个这样的表:

calendar:
    day 
------------
2011-01-01
2011-01-02
   ...

可以参与联接。我的意图是将日期范围维持在日历以匹配 t 中的日期范围。

编辑: 关于我正在寻找什么的更多注释,只是为了具体:

在生成 t_fill 时,我想完全涵盖 t 中的日期范围,以及两者之间缺少的日期范围。因此,正确的 t_fill 将在同一日期开始,并在与 t 相同的日期结束。 t_fill 有两个属性:

1)一旦id出现在某个日期,每个日期都会有一行。这是原始问题中隐含的填补空白。

2)如果没有行为一个id以后再一些日期之后出现,在 t_fill 溶液应该欢快产生从最后的数据点的日期与相同量度值的行(和0 DELTA)截至 t 的结束日期。

解决方案可能会将早期日期回填到 t 中日期范围的开头。也就是说,对于 t 中第一个日期之后显示的任何ID, t 中的第一个日期与ID的第一个日期之间的行将使用metric = 0填充和d_metric = 0。我不喜欢这种解决方案,因为它对于进入系统的每个id都有更高的增长因子。但我可以轻松地通过在新表中选择公式!= 0和d_metric!= 0的行来处理它。

4 个答案:

答案 0 :(得分:1)

这是关于Jonathan Leffler提出的建议,而是关于老式的低级 SQL(没有花哨的CTE或窗口函数或聚合子查询):

SET search_path='tmp'
DROP TABLE ttable CASCADE;
CREATE TABLE ttable
        ( zday date NOT NULL
        , id INTEGER NOT NULL
        , metric INTEGER NOT NULL
        , d_metric INTEGER NOT NULL
        , PRIMARY KEY (id,zday)
        );
INSERT INTO ttable(zday,id,metric,d_metric) VALUES
 ('2011-12-01',1,10,10)
,('2011-12-03',1,12,2)
,('2011-12-04',1,15,3)
        ;

DROP TABLE ctable CASCADE;
CREATE TABLE ctable
        ( zday date NOT NULL
        , PRIMARY KEY (zday)
        );
INSERT INTO ctable(zday) VALUES
 ('2011-12-01')
,('2011-12-02')
,('2011-12-03')
,('2011-12-04')
        ;

CREATE VIEW v_cte AS (
        SELECT t.zday,t.id,t.metric,t.d_metric
        FROM ttable t
        JOIN ctable c ON c.zday = t.zday
        UNION
        SELECT c.zday,t.id,t.metric, 0
        FROM ctable c, ttable t
        WHERE t.zday < c.zday
        AND NOT EXISTS ( SELECT *
                FROM ttable nx
                WHERE nx.id = t.id
                AND nx.zday = c.zday
                )
        AND NOT EXISTS ( SELECT *
                FROM ttable nx
                WHERE nx.id = t.id
                AND nx.zday < c.zday
                AND nx.zday > t.zday
                )
        )
        ;
SELECT * FROM v_cte;

结果:

    zday    | id | metric | d_metric 
------------+----+--------+----------
 2011-12-01 |  1 |     10 |       10
 2011-12-02 |  1 |     10 |        0
 2011-12-03 |  1 |     12 |        2
 2011-12-04 |  1 |     15 |        3
(4 rows)

答案 1 :(得分:0)

我不是Vertica用户,但如果您不想使用他们对GAP填充的原生支持,here您可以找到更通用的SQL解决方案。

答案 2 :(得分:0)

如果你想使用类似CTE的东西,那么如何使用临时表?实质上,CTE是特定查询的视图。

根据您的需要,您可以进行临时表事务或会话范围。

我仍然很想知道为什么使用常量插值填充间隙在这里不起作用。

答案 3 :(得分:0)

鉴于完整的日历表,它是可行的,但并非完全无关紧要。如果没有日历表,那将会更加困难。

您的查询需要适度准确地说明,这通常是“如何编写查询”的任何问题的一半。我想你正在寻找:

  • 对于日历中以T(或其他规定范围)表示的最小和最大日期之间的每个日期,
  • 对于T中表示的每个不同ID,
  • 在日期或之前的T中查找最新记录的给定ID的指标。

这为您提供了包含指标的完整日期列表。

然后,您需要自动加入该列表的两个副本,并将日期分开一天以形成增量。

请注意,如果某些ID值未显示在日期范围的开头,则不会显示。

以此作为指导,你应该能够开始,我相信。

相关问题