需要帮助在一行中的两个日期之间为每个月创建多行

Need assistance creating multiple rows for every month between two dates in one row

我正在尝试创建一个显示每个月的月收入的仪表板。我认为最好的方法是创建一个 table,每个月都有一行,旁边是收入。当前一行数据如下所示:

Subscription_ID|    Start_Date| End_Date    |Monthly_revenue
2384105        |    1/1/2016  | 6/1/2016    |500

我想以某种方式将该行转换为如下所示:

Subscription_ID |Month    |Monthly_Revenue
2384105         |1/1/2016 | 500
2384105         |2/1/2016 | 500
2384105         |3/1/2016 | 500
2384105         |4/1/2016 | 500
2384105         |5/1/2016 | 500
2384105         |6/1/2016 | 500

我什至不知道该怎么做。任何建议将不胜感激,或者如果你能指出我正确的方向。我使用 redshift 作为我的数据库,因此语法与 postgres 大体相似。

编辑:回复评论 - 如果有助于参考,我可以轻松地制作一个包含所有日期和年份的 table。

好的,我查看了一些 redshift 文档,像这样应该可以工作:

DATEDIFF http://docs.aws.amazon.com/redshift/latest/dg/r_DATEDIFF_function.html

常用 Table 表达式 http://docs.aws.amazon.com/redshift/latest/dg/r_WITH_clause.html

添加日期http://docs.aws.amazon.com/redshift/latest/dg/r_DATEADD_function.html

WITH cteData AS (
    SELECT 
       CAST(2384105 AS INTEGER) AS Subscription_ID
       ,CAST('2016-01-01' AS DATE) AS Start_Date
       ,CAST('2016-06-01' AS DATE) AS End_Date
       ,CAST(500 AS INTEGER) AS Monthly_revenue
)

,cteTally AS (
        SELECT 0 AS TallyNum
        UNION ALL
        SELECT 1
        UNION ALL
        SELECT 2
        UNION ALL
        SELECT 3
        UNION ALL
        SELECT 4
        UNION ALL
        SELECT 5
        UNION ALL
        SELECT 6
        UNION ALL
        SELECT 7
        UNION ALL
        SELECT 8
        UNION ALL
        SELECT 9
        UNION ALL
        SELECT 10
        UNION ALL
        SELECT 11
    )


    SELECT
        Subscription_ID
       ,DATEADD(month,c.TallyNum,t.Start_date) AS "Month"
        ,Monthly_revenue
    FROM
        cteData t
        INNER JOIN cteTally c
        ON DATEDIFF(month,t.Start_Date,t.End_Date) >= c.TallyNum

这可能对您有用,因为它不使用 generate_series() 或递归 cte。这是 postgresSQL 版本 我用 SQL Fiddle (http://sqlfiddle.com/#!15/f3a23/7/0) 试过这个...

CREATE TABLE Tbl (
  Subscription_ID INTEGER
  ,Start_Date DATE
  ,End_Date DATE
  ,Monthly_revenue INTEGER);

INSERT INTO Tbl (Subscription_ID, Start_Date, End_Date, Monthly_revenue)
VALUES (2384105,'2016-01-01','2016-06-01',500);

WITH cteTally AS (
    SELECT 0 AS TallyNum
    UNION ALL
    SELECT 1
    UNION ALL
    SELECT 2
    UNION ALL
    SELECT 3
    UNION ALL
    SELECT 4
    UNION ALL
    SELECT 5
    UNION ALL
    SELECT 6
    UNION ALL
    SELECT 7
    UNION ALL
    SELECT 8
    UNION ALL
    SELECT 9
    UNION ALL
    SELECT 10
    UNION ALL
    SELECT 11
)

SELECT
    Subscription_ID
    ,(t.Start_Date + (c.TallyNum * '1 month'::INTERVAL)) as "Month"
    ,Monthly_revenue
FROM
    Tbl t
    INNER JOIN cteTally c
    ON (
      (DATE_PART('year', t.End_Date) - DATE_PART('year', t.Start_Date)) * 12
      +
      (DATE_PART('month', t.End_Date) - DATE_PART('month', t.Start_Date))
    ) >= c.TallyNum
;