【问题标题】:Teradata SQL: Create volatile table with multiple rows automatically populated based on logicTeradata SQL:创建具有基于逻辑自动填充的多行的易失性表
【发布时间】:2018-02-02 02:32:28
【问题描述】:

我创建了一个脚本,该脚本创建了一个包含 3 列并插入 5 行的 volatile 表:

create multiset volatile table dr (
  period int
, st_date date
, end_date date
) 
primary index (period) on commit preserve rows;

insert into dr (period,st_date,end_date)
select *
from( select *
      from  (select   '201712' period
                    , '2017-10-01' st_date
                    , '2017-12-31' end_date
            )t1
      union all
      select *
      from  (select   '201612' period
                    , '2016-10-01' st_date
                    , '2016-12-31' end_date
            )t2
      union all
      select *
      from  (select   '201512' period
                    , '2015-10-01' st_date
                    , '2015-12-31' end_date
            )t3
      union all
      select *
      from  (select   '201412' period
                    , '2014-10-01' st_date
                    , '2014-12-31' end_date
            )t4
      union all
      select *
      from  (select   '201312' period
                    , '2013-10-01' st_date
                    , '2013-12-31' end_date
            )t5
    )t

我将把这个表格加入到其他几个表格的日期范围内。

在这里,我手动为每个插入的行键入信息,这有点麻烦且效率低下。

是否有更自动化的方法来执行此操作,并且所有时间都在一个日期(例如 2017-12-31)结束?我可以自己计算出逻辑,但不确定如何构造插入语句以允许这种逻辑。

谢谢!

编辑 我希望能够在任何连续 3 个月期间自动执行此操作,即使跨年(例如 2017-11-01 到 2018-01-31,或 2017-12-01 到 2018-02-28),然后继续在该连续 3 个月期间返回 5 年。

【问题讨论】:

  • 您总是想获得一个季度的月份还是连续三个月?
  • 连续 3 个月。我总是在连续 3 个月内检查数据。挑战总是跨年,例如从 2017-11-01 到 2018-01-31,或 2017-12-01 到 2018-02-28

标签: sql teradata


【解决方案1】:

我建议在宏中使用一些基于 TRUNC/ADD_MONTHS/LAST_DAY 的逻辑:

REPLACE MACRO testmac (in_date DATE)
AS
 (
   CREATE SET VOLATILE TABLE dr -- no need for MULTISET
   AS 
    (
      SELECT year_of_calendar * 100 + month_of_year AS PERIOD,
         Add_Months(calendar_date,-2) AS st_date, 
         Last_Day(calendar_date) AS end_date
      FROM sys_calendar.CALENDAR
      WHERE year_of_calendar -- current_month and two previous months
            BETWEEN Extract(YEAR From Add_Months(:in_date,-48))
                AND Extract(YEAR From :in_date)
        AND month_of_year = Extract(MONTH From :in_date)
        AND day_of_month = 1 -- only one row per year
    ) WITH DATA  
      UNIQUE PRIMARY INDEX (PERIOD)
      ON COMMIT PRESERVE ROWS;
 );

EXEC testmac(DATE '2018-01-22');

您还可以应用递归查询或 EXPAND ON。

编辑:

EXPAND ON 又好又短 :-)

SELECT Extract(YEAR From End(pd)) * 100 + Extract(MONTH From End(pd)) AS PERIOD
  ,Trunc(Add_Months(End(pd),-2), 'mon') AS st_date
  ,Last_Day(End(pd)) AS end_date
FROM sys_calendar.CALENDAR               -- specify the date once
WHERE calendar_date = DATE '2018-01-22'  -- or :in_date in the macro
EXPAND ON PERIOD(Add_Months(calendar_date,-60), calendar_date) AS pd
BY INTERVAL '1' YEAR -- one row per year

【讨论】:

  • 谢谢,这适用于所有情况。我在我们的生产系统上没有 CREATE MACRO 访问权限,所以我只是添加了一个“date '2018-01-31' as currdt”行,并将所有“:in_date”替换为“currdt”
  • @starfly:好吧,您可能在自己的用户中获得了 CREATE MACRO 访问权限(除非 DBA 明确撤销它)。您可以自己创建宏(和视图)(当然没有其他人,但您可以使用它)。
  • 我尝试使用您在上面提供的代码执行此操作,但收到一条错误消息,提示我没有 CREATE MACRO 访问权限。
  • @starfly:如果您尝试了REPLACE MACRO YourUser.YourMacro,但它失败了,您网站上的 DBA 可能会从用户那里撤销该权利,这是不常见的......
【解决方案2】:

您可以使用sys_calendar.calendar 表来推导这些周期,使用一些窗口函数变得有点狡猾:

SELECT distinct
    year_of_calendar * 100 + max(month_of_year) OVER (PARTITION BY year_of_calendar) as "period",
    min(calendar_date) OVER (PARTITION BY year_of_calendar) as st_date,
    max(calendar_date) OVER (PARTITION BY year_of_calendar) as end_date
FROM sys_calendar.calendar 
WHERE month_of_year BETWEEN 10 AND 12
    AND year_of_calendar BETWEEN 2013 AND 2017

+--------+------------+------------+
| period |  st_date   |  end_date  |
+--------+------------+------------+
| 201312 | 2013-10-01 | 2013-12-31 |
| 201412 | 2014-10-01 | 2014-12-31 |
| 201512 | 2015-10-01 | 2015-12-31 |
| 201612 | 2016-10-01 | 2016-12-31 |
| 201712 | 2017-10-01 | 2017-12-31 |
+--------+------------+------------+

将其包装到 CREATE TABLE 语句中:

CREATE MULTISET VOLATILE TABLE dr AS
(
    SELECT distinct
        year_of_calendar * 100 + max(month_of_year) OVER (PARTITION BY year_of_calendar) as "period",
        min(calendar_date) OVER (PARTITION BY year_of_calendar) as st_date,
        max(calendar_date) OVER (PARTITION BY year_of_calendar) as end_date
    FROM sys_calendar.calendar 
    WHERE month_of_year BETWEEN 10 AND 12
        AND year_of_calendar BETWEEN 2013 AND 2017
) 
WITH DATA
PRIMARY INDEX ("period")
ON COMMIT PRESERVE ROWS;

【讨论】:

  • 更新了答案以包含 CREATE TABLE 语句。
  • 谢谢,这确实简化了它。有没有办法进一步简化它?我仍然需要手动更新“10 到 12 之间”和“2013 到 2017 之间”语句。我尝试在顶部添加“date '2017-12-31 as currdt”(在 select 和 distinct 之间),然后在 between 语句中为每个部分提取月/月 -2 和年/年 -4。然后我收到一条错误消息:“预期在 ',' 和 'distinct' 关键字之间存在某些内容。
  • 另外,这仅在范围不跨越年份时才有效。如果我的日期范围是 2017-11-01 到 2018-01-31,它将返回一个空表。
  • 如果您从 2017-11-01 和 2018-01-31 开始,您的预期输出是什么?我假设 nov'17、dec'17 和 jan'18,但随后会您还希望这三个月/期间回到 2013 年吗?我猜......就像......你期待什么是这个输入,你期待什么作为该输入的输出?
  • 正确。因此,如果日期范围是 2017-11-01 到 2018-01-31,我希望看到“期间”= 201801、“st_date”= 2017-11-01、“end_date”= 2018-01-31。然后再回去4年(所以一直回到2013-11-01到2014-01-31)。期间很重要,因为我将在加入另外两个表之后按此分组,并将 st_date 和 end_date 作为日期范围传递给另外两个表。
猜你喜欢
  • 1970-01-01
  • 2013-06-11
  • 2013-11-29
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多