【问题标题】:Adding set lists of future dates to rows in a SQL query将未来日期的集合列表添加到 SQL 查询中的行
【发布时间】:2017-03-22 23:24:08
【问题描述】:

所以我正在为客户进行同期群分析,其中同期群是在同一个月开始使用该产品的一群人。然后,我会跟踪每个群组的总使用量,直到现在为止。

例如,第一个“队列月份”是 2012 年 1 月,然后我有“使用月份”1 月 12 日、2 月 12 日、3 月 12 日、...、3 月 17 日(当前月份)。一栏是“队列月份”,另一栏是“使用月份”。这个过程在随后的每个队列月重复。表格如下:

Jan 12 | Jan 12  
Jan 12 | Feb 12  
...   
Jan 12 | Mar 17  
Feb 12 | Feb 12  
Feb 12 | Mar 12  
...  
Feb 12 | Mar 17  
...  
Feb 17 | Feb 17  
Feb 17 | Mar 17  
Mar 17 | Mar 17  

出现问题是因为我想对现有和未来的同类群组进行一年的预测。 这意味着对于 1 月 12 日的队列,我想做 4 月 17 日到 3 月 18 日的预测。 我还想从 4 月 17 日到 3 月 18 日对 4 月 17 日的队列(尚不存在)进行预测。依此类推,直到 3 月 18 日对 3 月 18 日的队列进行预测。 我可以处理预测,不用担心。

我的问题是,在每个群组切换之前,我无法弄清楚如何在“使用月份”列中添加(4 月 17 日至 3 月 17 日)的列表。 我还需要添加 4 月 17 日至 3 月 18 日的群组,并为这些未来群组中的每一个提供(4 月 17 日至 3 月 17 日)列表的适用部分。

所以我希望表格看起来像:

Jan 12 | Jan 12  
Jan 12 | Feb 12  
...   
Jan 12 | Mar 17  
Jan 12 | Apr 17  
..    
Jan 12 | Mar 18  
Feb 12 | Feb 12  
Feb 12 | Mar 12  
...  
Feb 12 | Mar 17  
Feb 12 | Apr 17  
...  
Feb 12 | Mar 18  
...    
...    
Feb 17 | Feb 17  
Feb 17 | Mar 17    
...  
Feb 17 | Mar 18  
Mar 17 | Mar 17    
...  
Mar 17 | Mar 18  

我知道想到的第一个解决方案是创建一个包含 1 月 12 日至 3 月 18 日的所有日期的列表,将其交叉连接到自身,然后将外部连接左连接到我拥有的当前表(其中队列 / 使用月的范围从 1 月 12 日到 3 月 17 日)。但是,这是不可扩展的。

有没有一种方法可以迭代地添加到明年月份的列表中?

我正在使用 HP Vertica,如果绝对必要,可以使用 Presto 或 Hive

【问题讨论】:

    标签: sql vertica


    【解决方案1】:

    我认为您应该使用下面的查询从无到有地创建一个临时表,并将其与您的其余查询连接起来。恐怕你不能在 SQL 中以程序方式做任何事情。如果没有 CROSS JOIN,您将无法逃脱。但是在这里,您将 CROSS JOIN 限制为生成您需要的第一个月对。

    这里是:

    WITH
    -- create a list of integers from 0 to 100 using the TIMESERIES clause
    i(i) AS (
    SELECT dt::DATE - '2000-01-01'::DATE
    FROM ( 
              SELECT '2000-01-01'::DATE +   0 
    UNION ALL SELECT '2000-01-01'::DATE + 100
    ) d(d)
    TIMESERIES dt AS '1 day' OVER(ORDER BY d::TIMESTAMP)
    )
    ,
    -- limits are Jan-2012 to the first of the current month plus one year
    month_limits(month_limit) AS (
              SELECT '2012-01-01'::DATE
    UNION ALL SELECT ADD_MONTHS(TRUNC(CURRENT_DATE,'MONTH'),12)
    )
    -- create the list of possible months as a CROSS JOIN of the i table
    -- containing the integers and the month_limits table, using ADD_MONTHS()
    -- and the smallest and greatest month of the month limits
    ,month_list AS (
    SELECT
      ADD_MONTHS(MIN(month_limit),i) AS month_first
    FROM month_limits CROSS JOIN i
    GROUP BY i
    HAVING ADD_MONTHS(MIN(month_limit),i) <= (
      SELECT MAX(month_limit) FROM month_limits
      )
    )
    -- finally, CROSS JOIN the obtained month list with itself with the
    -- filters needed.
    SELECT
      cohort.month_first AS cohort_month
    , use.month_first    AS use_month
    FROM month_list AS cohort
    CROSS JOIN month_list AS use
    WHERE use.month_first >= cohort.month_first
    ORDER BY 1,2
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多