【数据处理】一条数据扩展成多条数据

文章介绍了在为证券公司开发估值、减值系统时,如何处理结构性存款模型中的数据扩展问题,特别是按照起息日、到期日和债券付息频率将数据扩展成多条。文中提到了使用Oracle的connectby和循环两种方式在数据库层面实现这一功能,分别展示了这两种方法的SQL实现代码,并给出了扩展前后的数据样式和示例。
摘要由CSDN通过智能技术生成

最近在给某家证券公司开发估值、减值系统,其中结构性存款模型有一处要对每一条数据按 起息日、到期日与债券付息频率 扩展成多条,扩展后每条的付息日期需在起息日的基础上按给定频率依次增加。

如果想在数据库中做这种处理,可以使用 connect by或循环 来实现。考虑到实际业务的需求实现较为复杂,这里做了简化,仅将重点放在数据库中一条数据如何扩展成多条数据上面。


扩展前后的数据样式


以如下两条数据为例,每条数据最终扩展会成几条,将由 结存起始日(D_PUTOUTDATE)结存到期日(D_MATURITY)债券付息频率(V_INTEREST_PAY_FREQ) 三者决定。

在这里插入图片描述

此处以债券付息频率M(月度Monthly)为例,扩展出的第一条数据的付息日期是在结存起始日基础上加30天(Monthly=30天),扩展出的第二条数据的付息日期在结存起始日基础上加60天… ,依次扩展下去,直到扩展出的最后一条的付息日期为不大于结存到期日的最大日期为止。如下即为以上两条样例数据扩展后的数据,可以看出交易编号为101的扩展出了2条,交易编号为102的扩展出了4条。

在这里插入图片描述


扩展的两种方式


为实现以上需求,可以使用connect by和循环两种方式。在此之前,先造出上面两条示例数据

--扩展前的测试数据
--drop table jc_str;
create table jc_str(
    D_DATA_DT date --数据日期
   ,D_PUTOUTDATE date --结存起始日
   ,D_MATURITY date --结存到期日
   ,V_TRADE_NO VARCHAR2(20) --交易编号
   ,V_INTEREST_PAY_FREQ VARCHAR2(20) --债券付息频率
);
insert into jc_str(D_DATA_DT,D_PUTOUTDATE,D_MATURITY,V_TRADE_NO,V_INTEREST_PAY_FREQ)
values(to_date('20211201','yyyymmdd'),to_date('20220101','yyyymmdd'),to_date('20220310','yyyymmdd'),'101','M');commit;
insert into jc_str(D_DATA_DT,D_PUTOUTDATE,D_MATURITY,V_TRADE_NO,V_INTEREST_PAY_FREQ)
values(to_date('20211201','yyyymmdd'),to_date('20220101','yyyymmdd'),to_date('20220501','yyyymmdd'),'102','M');commit;

--存储扩展后数据的表
--drop table jc_pay;
create table jc_pay(
    D_DATA_DT date --数据日期
   ,D_PUTOUTDATE date --结存起始日
   ,D_MATURITY date --结存到期日
   ,D_PAY_DATE date --付息日期
   ,V_TRADE_NO VARCHAR2(20) --交易编号
);

方式一:connect by

connect by方法适用于数据量不太大且没有复杂逻辑处理的数据扩展

declare
    kz_max int; --所有需要扩展的数据中,扩展条数最多的条数
begin

--扩展的最大条数
select max(kz_num) into kz_max from (
    select decode(V_INTEREST_PAY_FREQ
                 ,'M',floor((D_MATURITY-D_PUTOUTDATE)/30)
           ) as kz_num
    from jc_str
);

insert into jc_pay(
  D_DATA_DT
 ,D_PUTOUTDATE
 ,D_MATURITY
 ,D_PAY_DATE
 ,V_TRADE_NO
)
with temp1 as (
    select D_DATA_DT
          ,D_PUTOUTDATE
          ,D_MATURITY
          ,V_TRADE_NO
          ,V_INTEREST_PAY_FREQ
          ,decode(V_INTEREST_PAY_FREQ
                 ,'M',floor((D_MATURITY-D_PUTOUTDATE)/30)
           ) as kz_num --计算每条数据需要扩展出的条数
    from jc_str
)
select D_DATA_DT
      ,D_PUTOUTDATE
      ,D_MATURITY
      ,D_PUTOUTDATE+rn*decode(V_INTEREST_PAY_FREQ,'M',30) --计算付息日期
      ,V_TRADE_NO
from (--这里可以这样理解:每条数据都会先与括号里的connect by子句关联出kz_max条相同的数据(这kz_max条数据的rn从1到kz_max),然后筛选出rn<=kz_num(每条数据需要扩展出的条数)的数据,这样操作后每条数据只会留下自身要扩展的条数对应的数据。
    select a.*,b.rn
    from temp1 a
    inner join (select rownum rn from dual connect by level<=kz_max) b
    on b.rn<=a.kz_num
    --order by a.V_TRADE_NO,b.rn
);

end;

方式二:循环

循环适用于有复杂逻辑处理的数据扩展,比如每一条的扩展要按不同频率做不同处理

declare
    iter int:=1; --循环自增序列
    pl_num int; --频率码值转换
begin

--循环每条数据(外循环) 
for c in (
         select D_DATA_DT,D_PUTOUTDATE,D_MATURITY,V_TRADE_NO,V_INTEREST_PAY_FREQ
         from jc_str
         )
loop

--频率判断转换
IF c.V_INTEREST_PAY_FREQ='M' THEN
    pl_num:=30;
-- ELSIF c.PL='Q' THEN
--     pl_num:=120;
END IF;
	  --日期比较(内循环)
    while c.D_PUTOUTDATE+iter*pl_num<=c.D_MATURITY loop
        insert into jc_pay(D_DATA_DT
            ,D_PUTOUTDATE
            ,D_MATURITY
            ,D_PAY_DATE
            ,V_TRADE_NO
        )
        values(
            c.D_DATA_DT
           ,c.D_PUTOUTDATE
           ,c.D_MATURITY
           ,c.D_PUTOUTDATE+iter*pl_num --付息日期计算
           ,c.V_TRADE_NO
        );

        iter:=iter+1;
    end loop;

    iter:=1;
end loop;

end;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值