Teradata SQL: 通过自连接按指定时间间隔显示数据
Teradata SQL: Displaying data at specified time interval through self joins
我构建了这个长查询,它本质上是自我连接一堆表,但在不同的时间范围内以 3 个月的间隔提取余额,并将每个余额/时间段组合放在其自己的列中。
查询是这样的:
select
extract(year from a.mnth_end_dt) * 100 + extract(month from a.mnth_end_dt) as YM
,case when s.segmt_id = 'S4' then 'A'
else 'R'
end as Segment
,case when a.act_open_dt between add_months(a.mnth_end_dt + interval '1' day, -1) and a.mnth_end_dt then 'New'
else 'Old'
end as ACT_STAT
,count(distinct a.act_id) as ACTs
,coalesce(sum(b0.b1),0) as INT0_Tot_BD_Assets
,coalesce(sum(bk0.bal),0) as INT0_Tot_BNK_Cash
,INT0_Tot_BD_Assets + INT0_Tot_BNK_Cash as INT0_Tot_Assets
,coalesce(sum(b0.b2),0) as INT0_BS
,coalesce(sum(b0.b3),0) as INT0_BDC
,INT0_BS + INT0_BDC + INT0_Tot_BNK_Cash as INT0_Tot_Cash
,cast(cast(INT0_Tot_Cash as decimal(20,4)) / cast(INT0_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%' as INT0_Cash_Pct
,coalesce(sum(b1.b1),0) as INT1_Tot_BD_Assets
,coalesce(sum(bk1.bal),0) as INT1_Tot_BNK_Cash
,INT1_Tot_BD_Assets + INT1_Tot_BNK_Cash as INT1_Tot_Assets
,coalesce(sum(b1.b2),0) as INT1_BS
,coalesce(sum(b1.b3),0) as INT1_BDC
,INT1_BS + INT1_BDC + INT1_Tot_BNK_Cash as INT1_Tot_Cash
,case when INT1_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT1_Tot_Cash as decimal(20,4)) / cast(INT1_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT1_Cash_Pct
,coalesce(sum(b2.b1),0) as INT2_Tot_BD_Assets
,coalesce(sum(bk2.bal),0) as INT2_Tot_BNK_Cash
,INT2_Tot_BD_Assets + INT2_Tot_BNK_Cash as INT2_Tot_Assets
,coalesce(sum(b2.b2),0) as INT2_BS
,coalesce(sum(b2.b3),0) as INT2_BDC
,INT2_BS + INT2_BDC + INT2_Tot_BNK_Cash as INT2_Tot_Cash
,case when INT2_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT2_Tot_Cash as decimal(20,4)) / cast(INT2_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT2_Cash_Pct
from or.accts a
inner join ir.segments s
on a.clnt_cd = c.clnt_cd --segmt_lvl_nm# (6 highest level: AS/IS/Other Business)
and c.segmt_id in ('S4','S5')
left join ir.acct_bal_mthly b0
on a.acct_id = b0.acct_id
and b0.mnth_end_yyyymm = cast(extract(year from a.mnth_end_dt) * 100 + (extract(month from a.mnth_end_dt)) as integer)
left join ir.acct_bal_mthly b1
on a.acct_id = b1.acct_id
and b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)
left join ir.acct_bal_mthly_1 b2
on a.acct_id = b2.acct_id
and b2.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)
left join br.bank_bal_mnth bk0
on a.s_acct_id = bk0.bk_acct_nbr
and bk0.busn_dt = a.mnth_end_dt
left join br.bank_bal_mnth bk1
on a.s_acct_id = bk1.bk_acct_nbr
and bk1.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
left join br.bank_bal_mnth bk2
on a.s_acct_id = bk2.bk_acct_nbr
and bk2.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 6) - interval '1' day)
where a.mnth_end_dt between '2014-01-31' and '2018-04-30'
and a.acct_clos_dt is null
group by 1,2,3
order by 1,2,3
这个查询完成了工作,但我想知道是否有更好/更有效的方法来做到这一点?我觉得这个查询会给服务器带来不必要的负担(实际查询要大得多,我在这里为这个问题缩短了它)。
如有任何想法,我们将不胜感激。谢谢!
使用如下的条件逻辑。我通过为您用别名 b2 注释掉 table 并在相应的选择中替换为 case 语句来进行演示。对 bk1 和 bk2 也重复相同的逻辑。可能需要一些格式化太抱歉...
select
extract(year from a.mnth_end_dt) * 100 + extract(month from a.mnth_end_dt) as YM
,case when s.segmt_id = 'S4' then 'A'
else 'R'
end as Segment
,case when a.act_open_dt between add_months(a.mnth_end_dt + interval '1' day, -1) and a.mnth_end_dt then 'New'
else 'Old'
end as ACT_STAT
,count(distinct a.act_id) as ACTs
,coalesce(sum(b0.b1),0) as INT0_Tot_BD_Assets
,coalesce(sum(bk0.bal),0) as INT0_Tot_BNK_Cash
,INT0_Tot_BD_Assets + INT0_Tot_BNK_Cash as INT0_Tot_Assets
,coalesce(sum(b0.b2),0) as INT0_BS
,coalesce(sum(b0.b3),0) as INT0_BDC
,INT0_BS + INT0_BDC + INT0_Tot_BNK_Cash as INT0_Tot_Cash
,cast(cast(INT0_Tot_Cash as decimal(20,4)) / cast(INT0_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%' as INT0_Cash_Pct
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b1 else null end),
,coalesce(sum(bk1.bal),0) as INT1_Tot_BNK_Cash
,INT1_Tot_BD_Assets + INT1_Tot_BNK_Cash as INT1_Tot_Assets
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b2 else null end),
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b3 else null end),
,INT1_BS + INT1_BDC + INT1_Tot_BNK_Cash as INT1_Tot_Cash
,case when INT1_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT1_Tot_Cash as decimal(20,4)) / cast(INT1_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT1_Cash_Pct
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b1 else null end),
,coalesce(sum(bk2.bal),0) as INT2_Tot_BNK_Cash
,INT2_Tot_BD_Assets + INT2_Tot_BNK_Cash as INT2_Tot_Assets
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b2 else null end),
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b3 else null end),
,INT2_BS + INT2_BDC + INT2_Tot_BNK_Cash as INT2_Tot_Cash
,case when INT2_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT2_Tot_Cash as decimal(20,4)) / cast(INT2_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT2_Cash_Pct
from or.accts a
inner join ir.segments s
on a.clnt_cd = c.clnt_cd --segmt_lvl_nm# (6 highest level: AS/IS/Other Business)
and c.segmt_id in ('S4','S5')
left join ir.acct_bal_mthly b0
on a.acct_id = b0.acct_id
and b0.mnth_end_yyyymm = cast(extract(year from a.mnth_end_dt) * 100 + (extract(month from a.mnth_end_dt)) as integer)
left join ir.acct_bal_mthly b1
on a.acct_id = b1.acct_id
and b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)
--left join ir.acct_bal_mthly_1 b2
-- on a.acct_id = b2.acct_id
-- and b2.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)
left join br.bank_bal_mnth bk0
on a.s_acct_id = bk0.bk_acct_nbr
and bk0.busn_dt = a.mnth_end_dt
left join br.bank_bal_mnth bk1
on a.s_acct_id = bk1.bk_acct_nbr
and bk1.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
left join br.bank_bal_mnth bk2
on a.s_acct_id = bk2.bk_acct_nbr
and bk2.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 6) - interval '1' day)
where a.mnth_end_dt between '2014-01-31' and '2018-04-30'
and a.acct_clos_dt is null
group by 1,2,3
order by 1,2,3
当相同的 table 以相同的连接条件和不同的附加条件多次连接时,可以将其替换为单个连接加上 条件聚合 :
select
...
,sum(case when bk.busn_dt = a.mnth_end_dt then bk.bal else 0) as INT0_Tot_BNK_Cash
...
,sum(case when bk.busn_dt = oadd_months(a.mnth_end_dt, 3) then bk.bal else 0) as INT1_Tot_BNK_Cash
...
,sum(case when bk.busn_dt = oadd_months(a.mnth_end_dt, 6) then bk.bal else 0) as INT2_Tot_BNK_Cash
...
left join br.bank_bal_mnth bk
on a.s_acct_id = bk.bk_acct_nbr
and ( bk.busn_dt = a.mnth_end_dt
or bk.busn_dt = oadd_months(a.mnth_end_dt, 3)
or bk.busn_dt = oadd_months(a.mnth_end_dt, 6)
)
oadd_months(a.mnth_end_dt, 3)
是 (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
的重写
与 acct_bal_mthly
的联接类似
我构建了这个长查询,它本质上是自我连接一堆表,但在不同的时间范围内以 3 个月的间隔提取余额,并将每个余额/时间段组合放在其自己的列中。
查询是这样的:
select
extract(year from a.mnth_end_dt) * 100 + extract(month from a.mnth_end_dt) as YM
,case when s.segmt_id = 'S4' then 'A'
else 'R'
end as Segment
,case when a.act_open_dt between add_months(a.mnth_end_dt + interval '1' day, -1) and a.mnth_end_dt then 'New'
else 'Old'
end as ACT_STAT
,count(distinct a.act_id) as ACTs
,coalesce(sum(b0.b1),0) as INT0_Tot_BD_Assets
,coalesce(sum(bk0.bal),0) as INT0_Tot_BNK_Cash
,INT0_Tot_BD_Assets + INT0_Tot_BNK_Cash as INT0_Tot_Assets
,coalesce(sum(b0.b2),0) as INT0_BS
,coalesce(sum(b0.b3),0) as INT0_BDC
,INT0_BS + INT0_BDC + INT0_Tot_BNK_Cash as INT0_Tot_Cash
,cast(cast(INT0_Tot_Cash as decimal(20,4)) / cast(INT0_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%' as INT0_Cash_Pct
,coalesce(sum(b1.b1),0) as INT1_Tot_BD_Assets
,coalesce(sum(bk1.bal),0) as INT1_Tot_BNK_Cash
,INT1_Tot_BD_Assets + INT1_Tot_BNK_Cash as INT1_Tot_Assets
,coalesce(sum(b1.b2),0) as INT1_BS
,coalesce(sum(b1.b3),0) as INT1_BDC
,INT1_BS + INT1_BDC + INT1_Tot_BNK_Cash as INT1_Tot_Cash
,case when INT1_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT1_Tot_Cash as decimal(20,4)) / cast(INT1_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT1_Cash_Pct
,coalesce(sum(b2.b1),0) as INT2_Tot_BD_Assets
,coalesce(sum(bk2.bal),0) as INT2_Tot_BNK_Cash
,INT2_Tot_BD_Assets + INT2_Tot_BNK_Cash as INT2_Tot_Assets
,coalesce(sum(b2.b2),0) as INT2_BS
,coalesce(sum(b2.b3),0) as INT2_BDC
,INT2_BS + INT2_BDC + INT2_Tot_BNK_Cash as INT2_Tot_Cash
,case when INT2_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT2_Tot_Cash as decimal(20,4)) / cast(INT2_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT2_Cash_Pct
from or.accts a
inner join ir.segments s
on a.clnt_cd = c.clnt_cd --segmt_lvl_nm# (6 highest level: AS/IS/Other Business)
and c.segmt_id in ('S4','S5')
left join ir.acct_bal_mthly b0
on a.acct_id = b0.acct_id
and b0.mnth_end_yyyymm = cast(extract(year from a.mnth_end_dt) * 100 + (extract(month from a.mnth_end_dt)) as integer)
left join ir.acct_bal_mthly b1
on a.acct_id = b1.acct_id
and b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)
left join ir.acct_bal_mthly_1 b2
on a.acct_id = b2.acct_id
and b2.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)
left join br.bank_bal_mnth bk0
on a.s_acct_id = bk0.bk_acct_nbr
and bk0.busn_dt = a.mnth_end_dt
left join br.bank_bal_mnth bk1
on a.s_acct_id = bk1.bk_acct_nbr
and bk1.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
left join br.bank_bal_mnth bk2
on a.s_acct_id = bk2.bk_acct_nbr
and bk2.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 6) - interval '1' day)
where a.mnth_end_dt between '2014-01-31' and '2018-04-30'
and a.acct_clos_dt is null
group by 1,2,3
order by 1,2,3
这个查询完成了工作,但我想知道是否有更好/更有效的方法来做到这一点?我觉得这个查询会给服务器带来不必要的负担(实际查询要大得多,我在这里为这个问题缩短了它)。
如有任何想法,我们将不胜感激。谢谢!
使用如下的条件逻辑。我通过为您用别名 b2 注释掉 table 并在相应的选择中替换为 case 语句来进行演示。对 bk1 和 bk2 也重复相同的逻辑。可能需要一些格式化太抱歉...
select
extract(year from a.mnth_end_dt) * 100 + extract(month from a.mnth_end_dt) as YM
,case when s.segmt_id = 'S4' then 'A'
else 'R'
end as Segment
,case when a.act_open_dt between add_months(a.mnth_end_dt + interval '1' day, -1) and a.mnth_end_dt then 'New'
else 'Old'
end as ACT_STAT
,count(distinct a.act_id) as ACTs
,coalesce(sum(b0.b1),0) as INT0_Tot_BD_Assets
,coalesce(sum(bk0.bal),0) as INT0_Tot_BNK_Cash
,INT0_Tot_BD_Assets + INT0_Tot_BNK_Cash as INT0_Tot_Assets
,coalesce(sum(b0.b2),0) as INT0_BS
,coalesce(sum(b0.b3),0) as INT0_BDC
,INT0_BS + INT0_BDC + INT0_Tot_BNK_Cash as INT0_Tot_Cash
,cast(cast(INT0_Tot_Cash as decimal(20,4)) / cast(INT0_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%' as INT0_Cash_Pct
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b1 else null end),
,coalesce(sum(bk1.bal),0) as INT1_Tot_BNK_Cash
,INT1_Tot_BD_Assets + INT1_Tot_BNK_Cash as INT1_Tot_Assets
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b2 else null end),
,coalesce(sum(case when b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)),0) then b3 else null end),
,INT1_BS + INT1_BDC + INT1_Tot_BNK_Cash as INT1_Tot_Cash
,case when INT1_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT1_Tot_Cash as decimal(20,4)) / cast(INT1_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT1_Cash_Pct
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b1 else null end),
,coalesce(sum(bk2.bal),0) as INT2_Tot_BNK_Cash
,INT2_Tot_BD_Assets + INT2_Tot_BNK_Cash as INT2_Tot_Assets
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b2 else null end),
,coalesce(sum(case when mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)),0) then b3 else null end),
,INT2_BS + INT2_BDC + INT2_Tot_BNK_Cash as INT2_Tot_Cash
,case when INT2_Tot_Cash = 0 then 0 || '%'
else cast(cast(INT2_Tot_Cash as decimal(20,4)) / cast(INT2_Tot_Assets as decimal(20,4)) as decimal(20,4)) * 100 || '%'
end as INT2_Cash_Pct
from or.accts a
inner join ir.segments s
on a.clnt_cd = c.clnt_cd --segmt_lvl_nm# (6 highest level: AS/IS/Other Business)
and c.segmt_id in ('S4','S5')
left join ir.acct_bal_mthly b0
on a.acct_id = b0.acct_id
and b0.mnth_end_yyyymm = cast(extract(year from a.mnth_end_dt) * 100 + (extract(month from a.mnth_end_dt)) as integer)
left join ir.acct_bal_mthly b1
on a.acct_id = b1.acct_id
and b1.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,3)) * 100 + (extract(month from add_months(a.mnth_end_dt,3))) as integer)
--left join ir.acct_bal_mthly_1 b2
-- on a.acct_id = b2.acct_id
-- and b2.mnth_end_yyyymm = cast(extract(year from add_months(a.mnth_end_dt,6)) * 100 + (extract(month from add_months(a.mnth_end_dt,6))) as integer)
left join br.bank_bal_mnth bk0
on a.s_acct_id = bk0.bk_acct_nbr
and bk0.busn_dt = a.mnth_end_dt
left join br.bank_bal_mnth bk1
on a.s_acct_id = bk1.bk_acct_nbr
and bk1.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
left join br.bank_bal_mnth bk2
on a.s_acct_id = bk2.bk_acct_nbr
and bk2.busn_dt = (add_months(a.mnth_end_dt + interval '1' day, 6) - interval '1' day)
where a.mnth_end_dt between '2014-01-31' and '2018-04-30'
and a.acct_clos_dt is null
group by 1,2,3
order by 1,2,3
当相同的 table 以相同的连接条件和不同的附加条件多次连接时,可以将其替换为单个连接加上 条件聚合 :
select
...
,sum(case when bk.busn_dt = a.mnth_end_dt then bk.bal else 0) as INT0_Tot_BNK_Cash
...
,sum(case when bk.busn_dt = oadd_months(a.mnth_end_dt, 3) then bk.bal else 0) as INT1_Tot_BNK_Cash
...
,sum(case when bk.busn_dt = oadd_months(a.mnth_end_dt, 6) then bk.bal else 0) as INT2_Tot_BNK_Cash
...
left join br.bank_bal_mnth bk
on a.s_acct_id = bk.bk_acct_nbr
and ( bk.busn_dt = a.mnth_end_dt
or bk.busn_dt = oadd_months(a.mnth_end_dt, 3)
or bk.busn_dt = oadd_months(a.mnth_end_dt, 6)
)
oadd_months(a.mnth_end_dt, 3)
是 (add_months(a.mnth_end_dt + interval '1' day, 3) - interval '1' day)
与 acct_bal_mthly