Teradata SQL:创建基于逻辑自动填充多行的易失性表

时间:2018-02-01 17:22:19

标签: sql teradata

我创建了一个脚本,用于创建一个包含3列的易失性表,并插入5行:

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?我可以自己解决逻辑问题,但不知道如何构造insert语句以允许这种逻辑。

谢谢!

修改 我希望能够连续3个月自动完成这项工作,也可以在跨越年份时自动化(例如2017-11-01至2018-01-31,或2017-12-01至2018-02-28),然后继续连续3个月回来5年。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:2)

I would suggest using some logic based on TRUNC/ADD_MONTHS/LAST_DAY in a macro:

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');

You could also apply a recursive query or EXPAND ON.

Edit:

EXPAND ON is nice & short :-)

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
相关问题