簡體   English   中英

如何計算表 SQL Vertica 中到和之后的天數?

[英]How to calculate days to and after in table SQL Vertica?

我有 SQL 表,如下所示:

date        col1
2020-01-02  xxx

我有特殊的日期2020-01-01, 2020-01-05, 2020-05-10
我需要計算到最近的特殊日期的天數和最后一個特殊日期之后的天數,所以我需要如下結果:

next_special = 3 因為最接近 2020-01-02 的特殊日期是 2020-01-05(3 天)
last_special = 1 因為 2020-01-02 的最后一個特殊日期是 1 天前 (2020-01-01)

date        col1  next_special  last_special
2020-01-02  xxx   3             1

如果我理解正確,您可以使用復雜的case表達式以及least()greatest()

select t.*,
       nullif( least(case when '2020-01-01' < date then datediff(day, '2020-01-01', date) else 999999 end,
                     case when '2020-01-05' < date then datediff(day, '2020-01-05', date) else 999999 end,
                     case when '2020-05-10' < date then datediff(day, '2020-05-10', date) else 999999 end
                    ), 999999
             ) as prev_special,
       nullif( least(case when '2020-01-01' > date then datediff(day, date, '2020-01-01') else 999999 end,
                     case when '2020-01-05' > date then datediff(day, date, '2020-01-05') else 999999 end,
                     case when '2020-05-10' > date then datediff(day, date, '2020-05-10') else 999999 end
                    ), 999999
             ) as next_special
from t;

我認為這在幾乎任何其他數據庫中都更容易表達——因為它們支持SELECT子句中的相關標量子查詢。

編輯:

如果您在單獨的表中有值,並且在原始表中有唯一的 id,則可以使用:

select t.date, t.col1,
       min(case when d.date < t.date then datediff(day, d.date, t.date end) as prev_special,
       min(case when d.date > t.date then datediff(day, t.date, d.date end) as next_special
from t cross join
     dates d
group by t.date, t.col1;

更容易表達。 性能方面要差得多。

Vertica 使用事件系列 join ,它是使用 LEFT JOIN 子句中的INTERPOLATE PREVIOUS VALUE謂詞獲得的。 您可以從前一行獲取數據,而不是 LEFT JOIN 中的 NULLS。

Vertica 非常擅長 OLAP 函數 - 以及管道並行性,因此嵌套多個查詢通常會少一些傷害。

在下面的示例中,我在兩個限制日期中創建了一系列 15 個連續日期,從 1 月 1 日到 1 月 15 日,在indata中添加 'xxx' 作為 col1,並加入一個specdays表(在使用其后繼豐富每一行之后日期),然后應用事件系列連接和數學。

這就是你所追求的嗎?

WITH
specdays(dt) AS (
          SELECT DATE '2020-01-01' -- new year's day
UNION ALL SELECT DATE '2020-01-03' -- sunday
UNION ALL SELECT DATE '2020-01-06' -- epiphany
UNION ALL SELECT DATE '2020-01-10' -- sunday
)
,
prevnext AS (
  SELECT
    dt
, LEAD(dt) OVER w AS nextdt
FROM specdays
WINDOW w AS (ORDER BY dt)
)
,
-- list of dates beween 1st Jan and 15th Jan
indata AS (
SELECT
  tms::DATE AS dt
, 'xxx'     AS col1
FROM (
          SELECT TIMESTAMP '2020-01-01' 
UNION ALL SELECT TIMESTAMP '2020-01-15' 
) limits(dt)
TIMESERIES tms AS '1 DAY' OVER(ORDER BY dt)
)
SELECT 
  indata.* 
, prevnext.dt     AS prevspecday
, prevnext.nextdt AS nextspecday
, TIMESTAMPDIFF('DAY',prevnext.dt    ,indata.dt  ) AS last_special
, CASE WHEN prevnext.dt = indata.dt
    THEN 0
    ELSE TIMESTAMPDIFF('DAY',indata.dt  ,prevnext.nextdt)
  END AS next_special
FROM indata
LEFT JOIN prevnext ON indata.dt INTERPOLATE PREVIOUS VALUE prevnext.dt
;

dt        |col1|prevspecday|nextspecday|last_special|next_special
2020-01-01|xxx |2020-01-01 |2020-01-03 |           0|           0
2020-01-02|xxx |2020-01-01 |2020-01-03 |           1|           1
2020-01-03|xxx |2020-01-03 |2020-01-06 |           0|           0
2020-01-04|xxx |2020-01-03 |2020-01-06 |           1|           2
2020-01-05|xxx |2020-01-03 |2020-01-06 |           2|           1
2020-01-06|xxx |2020-01-06 |2020-01-10 |           0|           0
2020-01-07|xxx |2020-01-06 |2020-01-10 |           1|           3
2020-01-08|xxx |2020-01-06 |2020-01-10 |           2|           2
2020-01-09|xxx |2020-01-06 |2020-01-10 |           3|           1
2020-01-10|xxx |2020-01-10 |-          |           0|           0
2020-01-11|xxx |2020-01-10 |-          |           1|-
2020-01-12|xxx |2020-01-10 |-          |           2|-
2020-01-13|xxx |2020-01-10 |-          |           3|-
2020-01-14|xxx |2020-01-10 |-          |           4|-
2020-01-15|xxx |2020-01-10 |-          |           5|-

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM