此处给出的查询和例程的验证是在 DB2 for IBM i 7.3 [aka v7r3] 上完成的
没有说明如何使用数据 [以便了解需要或可以以何种形式提供数据],但以下用户定义的表函数 (UDTF) 定义了一些常量,这些常量表示来自传入的 MONTH [作为输入的可选日期;如果没有提供参数,则默认为 CURRENT DATE]、季末和半年末的月份以及季度;该映射允许一些相当简单的日期算术来提供所需的值,而无需创建实际的 [持久] 日历表:
create function OUR_FINANCIAL_YEAR_DATES
( input_date date default current date )
returns table
( "Last_Day_Of_Quarter" /* for LD_QTR */ date
, "Last_Day_Of_Half_Year" /* for LD_HALF */ date
, "Last_Day_Of_Year" /* for LD_YEAR */ date
) language sql
return
with
moMap ( mo, hAddMo, qAddMo, q ) as ( values
( 12, 3 , 0 , 3 ), ( 11, 4 , 1 , 3 ), ( 10, 5 , 2 , 3 )
, ( 9, 0 , 0 , 2 ), ( 8, 1 , 1 , 2 ), ( 7, 2 , 2 , 2 )
, ( 6, 3 , 0 , 1 ), ( 5, 4 , 1 , 1 ), ( 4, 5 , 2 , 1 )
, ( 3, 0 , 0 , 4 ), ( 2, 1 , 1 , 4 ), ( 1, 2 , 2 , 4 ) )
, endFYdates ( end_Qtr, end_Hyr, end_Fyr ) as
( select
last_day( input_date + qAddMo MONTHS ) as Qtr_end
, last_day( input_date + hAddMo MONTHS ) as Hyr_end
, last_day( input_date + (qAddMo + ( 3 * ( 4 - q ) )
) MONTHS ) as Fyr_end
from moMap as M
where mo = month( input_date )
)
select end_Qtr, end_Hyr, end_Fyr
from endFYdates
当然,标量用户定义函数 (UDF) 可以很容易地使用上述 UDTF 来实现获取其中任何一个值;可能带有第二个参数,用于标识要返回哪些 DATE 值。
with
variousDates ( dv ) as ( values
( date'2016-05-01' ), ( date'2016-05-02' ), ( date'2016-06-30' )
, ( date'2016-07-02' ), ( date'2016-08-02' ), ( date'2016-09-30' )
, ( date'2016-10-01' ), ( date'2016-11-02' ), ( date'2016-12-30' )
, ( date'2017-01-02' ), ( date'2017-03-02' ), ( date'2017-03-30' ) )
select vdv.*, fyv.*
, dec( quarter( vdv.dv - 3 months ) , 1 ) as qtr
from variousDates as vdv
, lateral
( select s.* from table(OUR_FINANCIAL_YEAR_DATES(vdv.dv)) as s
) as fyv
order by 1
; -- a likeness of a report from the above query:
DV LAST_00001 LAST_00002 LAST_00003 QTR
2016-05-01 2016-06-30 2016-09-30 2017-03-31 1
2016-05-02 2016-06-30 2016-09-30 2017-03-31 1
2016-06-30 2016-06-30 2016-09-30 2017-03-31 1
2016-07-02 2016-09-30 2016-09-30 2017-03-31 2
2016-08-02 2016-09-30 2016-09-30 2017-03-31 2
2016-09-30 2016-09-30 2016-09-30 2017-03-31 2
2016-10-01 2016-12-31 2017-03-31 2017-03-31 3
2016-11-02 2016-12-31 2017-03-31 2017-03-31 3
2016-12-30 2016-12-31 2017-03-31 2017-03-31 3
2017-01-02 2017-03-31 2017-03-31 2017-03-31 4
2017-03-02 2017-03-31 2017-03-31 2017-03-31 4
2017-03-30 2017-03-31 2017-03-31 2017-03-31 4
******** End of data ********
以下 UDTF 计算作为输入的给定 DATE 值的 End-Of-Quarter [对于 CURRENT_DATE,如果没有传递参数],但另外计算并提供 Start-Of-从该计算日期开始的每个季度的 Quarter 和 End-Of_Quarter 值,加上提供给定 DATE 值的半年末、年末和季度的计算结果:
create function THE_FINANCIAL_YEAR_DATES
( input_date date default current date )
returns table
( LastOfQtr /* for LD_QTR */ date
, LastOfHalf /* for LD_HALF */ date
, LastOfYear /* for LD_YEAR */ date
, NumberQtr /* for NO_QTR */ dec(1)
, FirstOfQ1 /* for FD_Q1 */ date
, Last_OfQ1 /* for LD_Q1 */ date
, FirstOfQ2 /* for FD_Q2 */ date
, Last_OfQ2 /* for LD_Q2 */ date
, FirstOfQ3 /* for FD_Q3 */ date
, Last_OfQ3 /* for LD_Q3 */ date
, FirstOfQ4 /* for FD_Q4 */ date
, Last_OfQ4 /* for LD_Q4 */ date
) language sql
return
with
endCurQtr ( ecq , q ) as
( values
( LAST_DAY( input_date
+ ( MOD( 1 - MONTH( input_date )
, 3 ) + 2
) MONTHS
)
, DEC( QUARTER( input_date - 3 MONTHS ), 1 )
)
)
, curFYdates (q, ecq, sQ1, eQ1, sQ2, eQ2, sQ3, eQ3, sQ4, eQ4, eHY) as
( select q, ecq,
( ecq + 1 day ) - ( 3 * ( q ) ) months
, last_day( ( ecq ) - ( 3 * ( q - 1 ) ) months )
, ( ecq + 1 day ) - ( 3 * ( q - 1 ) ) months
, last_day( ( ecq ) - ( 3 * ( q - 2 ) ) months )
, ( ecq + 1 day ) - ( 3 * ( q - 2 ) ) months
, last_day( ( ecq ) - ( 3 * ( q - 3 ) ) months )
, ( ecq + 1 day ) - ( 3 * ( q - 3 ) ) months
, last_day( ( ecq ) - ( 3 * ( q - 4 ) ) months )
, last_day( ( ecq ) - ( 3 * ( q -
case when q>2 then 4 else 2 end) ) months )
from endCurQtr
)
select ecq, eHY, eQ4, q, sQ1, eQ1, sQ2, eQ2, sQ3, eQ3, sQ4, eQ4
from curFYdates