【问题标题】:Get quarter start/end dates for more than a year (start year to current year)获取超过一年的季度开始/结束日期(开始年份到当年)
【发布时间】:2021-04-12 09:16:11
【问题描述】:

我一直在尝试在给定特定日期/年份的情况下获取每个季度的开始和结束日期范围,如下所示:

 SELECT DATEADD(mm, (quarter - 1) * 3, year_date) StartDate,
       DATEADD(dd, 0, DATEADD(mm, quarter * 3, year_date)) EndDate
       --quarter QuarterNo
  FROM
(
  SELECT '2012-01-01' year_date
) s CROSS JOIN 
(
  SELECT 1 quarter UNION ALL
  SELECT 2 UNION ALL
  SELECT 3 UNION ALL
  SELECT 4
) q

产生以下输出:

2012-01-01 00:00:00 2012-04-01 00:00:00
2012-04-01 00:00:00 2012-07-01 00:00:00
2012-07-01 00:00:00 2012-10-01 00:00:00
2012-10-01 00:00:00 2013-01-01 00:00:00

问题:我需要为给定的 start_dateend_date 执行此操作,问题是 end_date=current_day,那么我该如何实现:

2012-01-01 00:00:00 2012-04-01 00:00:00
2012-04-01 00:00:00 2012-07-01 00:00:00
2012-07-01 00:00:00 2012-10-01 00:00:00
2012-10-01 00:00:00 2013-01-01 00:00:00
    ...   ...
2021-01-01 00:00:00   2021-01-06 00:00:00

【问题讨论】:

    标签: sql date snowflake-cloud-data-platform date-range


    【解决方案1】:

    我认为这就是你想要做的:

    SET startdatevar AS DATEtime = '2020-01-10' 
    ;WITH RECURSIVE cte AS (
    
    SELECT startdatevar AS startdate , DATEADD(QUARTER, 1  , startdatevar) enddate , 1 quarter
    UNION ALL 
    SELECT enddate , CASE WHEN DATEADD(QUARTER, 1  , enddate) > CURRENT_DATE() THEN GETDATE() ELSE DATEADD(QUARTER, 1  , enddate) END enddate, quarter + 1
    FROM cte 
    WHERE 
        cte.enddate <= CURRENT_DATE()
         and quarter < 4
    )
    
    
    SELECT * FROM cte
    

    使用您的代码,如果您想要超过 4 个季度:

    SET quarter_limit = DATEDIFF(quarter , <startdate>,<enddate>)
    ;WITH RECURSIVE cte(q, qDate,enddate) as
        (
            select 1,    
              DATEFROMPARTS(year('2012-01-01'::date), 1, 1) -- First quarter date
             ,time_slice('2012-01-01'::date, 3, 'MONTH', 'END')
             UNION ALL
             select q+1,
             DATEADD(q, 1, qdate) -- next quarter start date
             ,time_slice(qdate::date, (q+1)*3, 'MONTH', 'END')
             from cte
             where q < quarter_limit -- limiting the number of next quarters
             AND cte.endDate <= <enddate>
         )
         SELECT * FROM cte
    

    【讨论】:

    • 因为我现在无法访问雪花数据库,它可能不是 100% 正确的语法,但它应该可以工作,你得到的错误信息是什么(如果有的话)?跨度>
    【解决方案2】:

    @eshirvana的回答之后,我在你回答之后想出了这个小改动:

    WITH RECURSIVE cte(q, qDate,enddate) as
        (
            select 1,    
              DATEFROMPARTS(year('2012-01-01'::date), 1, 1) -- First quarter date
             ,time_slice('2012-01-01'::date, 3, 'MONTH', 'END')
             UNION ALL
             select q+1,
             DATEADD(q, 1, qdate) -- next quarter start date
             ,time_slice(qdate::date, (q+1)*3, 'MONTH', 'END')
             from cte
             where q <4 -- limiting the number of next quarters
             AND cte.endDate <= CURRENT_DATE() 
         )
         SELECT * FROM cte
    

    无论我通过那里的任何年份都可以正常工作(2012 年将产生 4 条记录,2021 年只有一条,因为我们现在仍处于第一季度)。

    [编辑]:在您的第二次代码建议之后,它仍然无法按预期工作:

     WITH RECURSIVE cte(q, qDate,enddate) as
        (
            select 1,    
              DATEFROMPARTS(year('2012-01-01'::date), 1, 1) -- First quarter date
             ,CASE  WHEN time_slice('2012-01-01'::date, 3, 'MONTH', 'END') > CURRENT_DATE
                THEN current_date 
                ELSE time_slice('2012-01-01'::date, 3, 'MONTH', 'END') 
                END
             UNION ALL
             select q+1,
             DATEADD(q, 1, qdate) -- next quarter start date
             ,time_slice(qdate::date, (q+1)*3, 'MONTH', 'END')
             from cte
             where q < DATEDIFF(quarter , '2012-01-01'::date,'2021-01-06'::date)
             AND cte.endDate <= '2021-01-06'::date
         )
         SELECT * FROM cte 
    

    正在输出: 抱歉@eshirvana,但它并没有按预期工作。在某种程度上一切都很顺利,但它并没有返回所有记录。相反,它会产生更少的记录和错误的记录,如下所示:

    1   2012-01-01  2012-04-01
    2   2012-04-01  2012-07-01
    3   2012-07-01  2012-10-01
    4   2012-10-01  2013-01-01
    5   2013-01-01  2013-10-01
    6   2013-04-01  2013-07-01
    7   2013-07-01  2013-10-01
    8   2013-10-01  2014-01-01
    9   2014-01-01  2015-01-01
    10  2014-04-01  2015-01-01
    11  2014-07-01  2016-10-01
    12  2014-10-01  2015-01-01
    13  2015-01-01  2015-07-01
    14  2015-04-01  2015-07-01
    15  2015-07-01  2018-10-01
    16  2015-10-01  2018-01-01
    17  2016-01-01  2016-10-01
    18  2016-04-01  2019-07-01
    19  2016-07-01  2017-07-01
    20  2016-10-01  2020-01-01
    21  2017-01-01  2017-04-01
    22  2017-04-01  2019-07-01
    23  2017-07-01  2021-10-01
    

    虽然我的逻辑仍然不能只打印 2021 年第一季度的日期,但这个输出问题是否与日期格式或其他什么有关?

    【讨论】:

    • 只需将 CURRENT_DATE() 替换为您想要的日期作为结束日期
    • 它不起作用。如果我为此选择其他日期,它将打印 2012 年的所有 4 start_dt/end_dt just。我想迭代几年,这意味着将其应用于 2012-01-01, 2013-01-01,...等等。它的主要思想就在那里,是的,但它只能工作一年。
    • 哦,我明白了,所以您需要通过查找开始日期和结束日期之间有多少个季度来计算级别 (q),请参阅我的更新答案
    【解决方案3】:

    现在,至少从 2012 年 1 月 1 日到今天(2021 年 1 月 6 日),它似乎有效。

    代码:

     WITH RECURSIVE cte(q, qDate,enddate) as
        (
            select 
            -- it might not be the first quarter, so better to protect that:
             quarter('2012-01-01'::date)::numeric 
            , DATEFROMPARTS(year('2012-01-01'::date), 1, 1) -- First quarter date
            , CASE WHEN time_slice('2012-01-01'::date, 3, 'MONTH', 'END') > '2021-01-06'::date
                THEN '2021-01-06'::date
                ELSE time_slice('2012-01-01'::date, 3, 'MONTH', 'END') 
                END
             UNION ALL
             select q+1
             , DATEADD(q, 1, qdate) -- next quarter start date
             ,CASE  WHEN time_slice(DATEADD(q, 1, qdate), 3, 'MONTH', 'END')> '2021-01-06'::date
                THEN '2021-01-06'::date
                ELSE time_slice(DATEADD(q, 1, qdate), 3, 'MONTH', 'END')
                END
             from cte
             where q <= DATEDIFF(quarter , '2012-01-01'::date,'2021-01-06'::date)
             AND cte.endDate <= '2021-01-06'::date
         )
         SELECT * FROM cte  
    

    输出:

    1   2012-01-01  2012-04-01
    2   2012-04-01  2012-07-01
    3   2012-07-01  2012-10-01
    4   2012-10-01  2013-01-01
    5   2013-01-01  2013-04-01
    6   2013-04-01  2013-07-01
    7   2013-07-01  2013-10-01
    8   2013-10-01  2014-01-01
    9   2014-01-01  2014-04-01
    10  2014-04-01  2014-07-01
    11  2014-07-01  2014-10-01
    12  2014-10-01  2015-01-01
    13  2015-01-01  2015-04-01
    14  2015-04-01  2015-07-01
    15  2015-07-01  2015-10-01
    16  2015-10-01  2016-01-01
    17  2016-01-01  2016-04-01
    18  2016-04-01  2016-07-01
    19  2016-07-01  2016-10-01
    20  2016-10-01  2017-01-01
    21  2017-01-01  2017-04-01
    22  2017-04-01  2017-07-01
    23  2017-07-01  2017-10-01
    24  2017-10-01  2018-01-01
    25  2018-01-01  2018-04-01
    26  2018-04-01  2018-07-01
    27  2018-07-01  2018-10-01
    28  2018-10-01  2019-01-01
    29  2019-01-01  2019-04-01
    30  2019-04-01  2019-07-01
    31  2019-07-01  2019-10-01
    32  2019-10-01  2020-01-01
    33  2020-01-01  2020-04-01
    34  2020-04-01  2020-07-01
    35  2020-07-01  2020-10-01
    36  2020-10-01  2021-01-01
    37  2021-01-01  2021-01-06
    

    如果您想知道:是的,我们的想法是将 end_date 表示为该月的 last_day+one。但它很容易适应。

    它不漂亮,但我认为它很容易理解。

    【讨论】:

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