sql总结
- 场景1分组后失败的成功数据带入
- 场景2完全性质的一对一匹配
- 场景3虚拟户的特殊匹配
- 场景4多对多匹配
- 场景5一对一匹配
- 场景6 一对多匹配
场景1分组后失败的成功数据带入
现有一批交易表的数据,根据户名,日期,金额分组,存在TRADE_STATUS 有成功和失败的情况,
而失败的FUNDFLOW_DETAILS_ID字段已和资金表的FUNDFLOW_DETAILS_ID匹配。
现需要将成功的凭证号和期间根据";"拼接到一起,存储到与该组失败数据匹配的资金表的数据中,存储到JOURNAL_VOUCHER_NUMBER和ACCOUNT_DATE 字段
使用
HAVING
sum(CASE WHEN a.TRADE_STATUS = ‘失败’ THEN 1 ELSE 0 END) >=1
AND
sum(CASE WHEN a.TRADE_STATUS = ‘成功’ THEN 1 ELSE 0 END) >=1
判断该分组下是否至少有一条成功的数据和一条失败的数据
DECLARE CURSOR res_data IS SELECT a.CUSTOMER_ACCOUNT_NAME_ORIGIN,TRUNC(a.TRADE_DATE_BAK) AS ts_date,a.TRADE_AMOUNTFROM RC_TRADEFLOW_DETAILS_NAPR aWHERE 1=1AND a.OURS_ACCOUNT_NUMBER LIKE '%02222' GROUP BY a.CUSTOMER_ACCOUNT_NAME_ORIGIN,TRUNC(a.TRADE_DATE_BAK),a.TRADE_AMOUNT HAVING sum(CASE WHEN a.TRADE_STATUS = '失败' THEN 1 ELSE 0 END) >=1ANDsum(CASE WHEN a.TRADE_STATUS = '成功' THEN 1 ELSE 0 END) >=1;a_vouchers varchar2(4000);a_periods varchar2(4000);
BEGIN FOR s IN res_data LOOPSELECT EXTRACT(XMLAGG(XMLELEMENT(e, pz, ';') ORDER BY pz),'/E/text()').GETCLOBVAL() INTO a_vouchersFROM (SELECT DISTINCT a.JOURNAL_VOUCHER_NUMBER as pzFROM RC_TRADEFLOW_DETAILS_NAPR a WHERE 1=1AND a.OURS_ACCOUNT_NUMBER LIKE '%2222'AND a.CUSTOMER_ACCOUNT_NAME_ORIGIN = s.CUSTOMER_ACCOUNT_NAME_ORIGINAND TRUNC(a.TRADE_DATE_BAK) = s.ts_dateAND a.TRADE_AMOUNT = s.TRADE_AMOUNTAND a.TRADE_STATUS = '成功');SELECT EXTRACT(XMLAGG(XMLELEMENT(e, qj, ';') ORDER BY qj),'/E/text()').GETCLOBVAL() INTO a_periodsFROM (SELECT DISTINCT a.ACCOUNT_DATE as qjFROM RC_TRADEFLOW_DETAILS_NAPR a WHERE 1=1AND a.OURS_ACCOUNT_NUMBER LIKE '%02222'AND a.CUSTOMER_ACCOUNT_NAME_ORIGIN = s.CUSTOMER_ACCOUNT_NAME_ORIGINAND TRUNC(a.TRADE_DATE_BAK) = s.ts_dateAND a.TRADE_AMOUNT = s.TRADE_AMOUNTAND a.TRADE_STATUS = '成功');UPDATE RC_FUNDFLOW_DETAILS_NAPR A SET a.JOURNAL_VOUCHER_NUMBER = a_vouchers,a.ACCOUNT_DATE = a_periods,a.RULER_NAME_TRADEFLOW = '失败和成功同一批次,失败已经和资金表的资金流水编号匹配,将成功的凭证号拼接带入那个资金'WHERE 1=1AND a.OURS_ACCOUNT_NUMBER LIKE '%02222'AND a.FUNDFLOW_DETAILS_ID IN (SELECT DISTINCT b.FUNDFLOW_DETAILS_ID FROM RC_TRADEFLOW_DETAILS_NAPR b WHERE 1=1AND b.OURS_ACCOUNT_NUMBER LIKE '%02222'AND b.CUSTOMER_ACCOUNT_NAME_ORIGIN = s.CUSTOMER_ACCOUNT_NAME_ORIGINAND TRUNC(b.TRADE_DATE_BAK) = s.ts_dateAND b.TRADE_AMOUNT = s.TRADE_AMOUNTAND b.TRADE_STATUS = '失败');END LOOP;COMMIT;
END;
场景2完全性质的一对一匹配
现有一批数据,企业表和交易表已经匹配大量数据,但还有剩余,剩余数据匹配规则如下:
1.两批数据必须在账户,户名,日期,金额分组下仅有一条,防止匹配错乱,
2.按照账户,户名,日期,金额进行匹配
3.将企业表的凭证号和期间带入资金。
使用窗口函数,在不影响性能的情况下,快速判断该数据在该分区下该条数据是否仅有一条
BEGINFOR s in (
SELECTqy.DOC_SEQUENCE_VALUE,qy.PERIOD_NAME,zj.URIDfrom(SELECTls.mydate,ls.CUSTOMER_NAME,ls.money,ls.DOC_SEQUENCE_VALUE,ls.PERIOD_NAMEFROM(SELECTTO_CHAR(DEFAULT_EFFECTIVE_DATE, 'YYYY-MM-dd') AS mydate,CUSTOMER_NAME,(CASE WHEN ENTERED_DR <> 0 THEN ENTERED_DR ELSE -ENTERED_CR end) AS money,DOC_SEQUENCE_VALUE,PERIOD_NAME,count(*) OVER(PARTITION BY TO_CHAR(DEFAULT_EFFECTIVE_DATE, 'YYYY-MM-dd'),CUSTOMER_NAME,ENTERED_DR,ENTERED_CR) AS partition_countFROM rc_fin_transactions WHERE 1=1 AND BANKACCNO_SID = (select sid from RC_BANKACCDEF where BANKACCNO like '%11111'))lsWHERE ls.partition_count = 1) qyINNER JOIN (SELECTls.mydate,ls.DF_ACCOUNTNAME,ls.AMOUNT,ls.URIDFROM(SELECTTO_CHAR(POSTDATETIME, 'YYYY-MM-dd') AS mydate,DF_ACCOUNTNAME,AMOUNT,URID,COUNT(*) OVER (PARTITION BY TO_CHAR(POSTDATETIME, 'YYYY-MM-dd'), DF_ACCOUNTNAME, AMOUNT) AS partition_countFROM ISSUE202412_RECON_ZJLSBWHERE wf_account LIKE '%11111' AND 企业账凭证号 IS NULL) lsWHERE ls.partition_count = 1) zjon qy.mydate = TO_CHAR(TO_DATE(zj.mydate,'YYYY-MM-DD')+1,'YYYY-MM-DD') AND qy.CUSTOMER_NAME = zj.DF_ACCOUNTNAME AND qy.money = zj.amount) LOOP
-- 将企业的凭证号和期间带入资金
update ISSUE202412_RECON_ZJLSB
set 企业账凭证号 = s.DOC_SEQUENCE_VALUE,企业账期间 = s.PERIOD_NAME,规则名称 = '日期+户名+单笔金额1对1企业直接带入资金'
where URID = s.URID;
END LOOP;
COMMIT;
END;
场景3虚拟户的特殊匹配
现有交易表和资金表数据,要求交易表和资金表按照日期(天)匹配,
规则:
1.如果交易表当天的所有数据能够资金表当天的数据按照日期(天)匹配,那就按当天匹配
2.如果资金表中当天不存在数据,那就找到比当前交易表日期小的资金表中存在的最大的日期进行匹配
3.如果资金表中既不存在当天数据,也不存在比当前交易表日期小的资金表中存在的最大的日期
那就找到比当前交易表日期大的资金表中存在的最小日期进行匹配。
总结:就近匹配
将与交易表当天匹配的资金表的那天的所有FUNDSFLOWCODE进行拼接,放入交易表当天的每一条数据中。
将日期匹配条件进行优化,
原先TRUNC(TRADE_DATE_BAK) = rec.TRADE_DATE_BAK 因为牵涉到函数计算字段,导致索引失效,
优化为范围查询,大大提升性能
AND d.postdatetime >= rec.TRADE_DATE_BAK
AND d.postdatetime < rec.TRADE_DATE_BAK + 1
优化原理,TRUNC会截取到日期的天如2025-01-03 23:33:13.111会被截取为2025-01-03 00:00:00.000
,故那天的所有日期都会被截取为2025-01-03 00:00:00.000,如果想获取当天的所有日期,仅需找到当天日期范围在
[2025-01-03 00:00:00.000,2025-01-04 00:00:00.000)也就是
AND d.postdatetime >= rec.TRADE_DATE_BAK
AND d.postdatetime < rec.TRADE_DATE_BAK + 1
DECLARECURSOR cur_data ISSELECT DISTINCT TRUNC(TRADE_DATE_BAK) AS TRADE_DATE_BAKFROM rc_tradeflow_details_napr -- 交易流水表WHERE OURS_ACCOUNT_NUMBER = '11111.com' AND ATTRIBUTE4 IS NULLORDER BY TRUNC(TRADE_DATE_BAK); cx_date DATE; SUM_FUNDSFLOWCODE VARCHAR2(4000);temp VARCHAR2(4000); commit_counter NUMBER := 0;
BEGINFOR rec IN cur_data LOOPBEGIN -- 找出与当前日期相同的日期SELECT TRUNC(d.postdatetime) INTO cx_dateFROM rc_fundflow_details_napr d -- 资金流水表WHERE 1=1AND d.MONEY_WAY ='充值'AND d.OURS_ACCOUNT_NUMBER in ('22222','33333','44444')AND d.CUSTOMER_ACCOUNT_NAME_ORIGIN = '支付宝(中国)网络技术有限公司'AND d.CUSTOMER_ACCOUNT_NUMBER = '88888'-- AND TRUNC(TRADE_DATE_BAK) = rec.TRADE_DATE_BAK AND d.postdatetime >= rec.TRADE_DATE_BAK -- 优化为范围查询AND d.postdatetime < rec.TRADE_DATE_BAK + 1AND ROWNUM = 1;EXCEPTIONWHEN NO_DATA_FOUND THEN cx_date := NULL;END;-- 找出比当前日期小的最大日期IF cx_date IS NULL THENSELECT MAX(TRUNC(d.postdatetime)) INTO cx_dateFROM rc_fundflow_details_napr d -- 资金流水表WHERE 1=1AND d.MONEY_WAY ='充值'AND d.OURS_ACCOUNT_NUMBER in ('22222','33333','44444')AND d.CUSTOMER_ACCOUNT_NAME_ORIGIN = '支付宝(中国)网络技术有限公司'AND d.CUSTOMER_ACCOUNT_NUMBER = '88888'AND d.postdatetime < rec.TRADE_DATE_BAK + INTERVAL '1' DAY;END IF;-- 找出比当前日期大的最小日期IF cx_date IS NULL THEN SELECT MIN(TRUNC(d.postdatetime)) INTO cx_dateFROM rc_fundflow_details_napr d -- 资金流水表WHERE 1=1AND d.MONEY_WAY ='充值'AND d.OURS_ACCOUNT_NUMBER in ('22222','33333','44444')AND d.CUSTOMER_ACCOUNT_NAME_ORIGIN = '支付宝(中国)网络技术有限公司'AND d.CUSTOMER_ACCOUNT_NUMBER = '88888'AND d.postdatetime > rec.TRADE_DATE_BAK;END IF;-- 拼接这些日期的交易流水编号SELECT (RTRIM(EXTRACT(XMLAGG(XMLELEMENT(e, FUNDSFLOWCODE, ';') ORDER BY FUNDSFLOWCODE),'/E/text()').GETCLOBVAL(),';')) INTO SUM_FUNDSFLOWCODEFROM(SELECTFUNDFLOW_DETAILS_ID AS FUNDSFLOWCODEFROM rc_fundflow_details_napr d -- 资金流水表WHERE 1=1AND d.MONEY_WAY ='充值'AND d.OURS_ACCOUNT_NUMBER in ('22222','33333','44444')AND d.CUSTOMER_ACCOUNT_NAME_ORIGIN = '支付宝(中国)网络技术有限公司'AND d.CUSTOMER_ACCOUNT_NUMBER = '88888'AND d.postdatetime >= cx_date AND d.postdatetime < cx_date +1);-- 更新交易流水表的本天的所有数据UPDATE rc_tradeflow_details_naprSET ATTRIBUTE4 = SUM_FUNDSFLOWCODEWHERE 1=1AND OURS_ACCOUNT_NUMBER = '11111.com' AND ATTRIBUTE4 IS NULLAND TRADE_DATE_BAK >= rec.TRADE_DATE_BAK AND TRADE_DATE_BAK < rec.TRADE_DATE_BAK+1;-- 增加计数器commit_counter := commit_counter + 1;-- 每处理一定数量的记录后提交一次事务IF commit_counter >= 50 THEN COMMIT;commit_counter := 0; -- 重置计数器END IF;END LOOP;COMMIT;
END;
场景4多对多匹配
现有一批数据,要求交易表按照账户,日期进行分组汇总得到汇总金额
资金表按照户名,日期进行分组得到汇总金额
按照日期,账户,汇总金额进行匹配,将交易表该组的所有凭证号和期间拼接带入资金表该组的每一条数据
将资金表该组的所有URID拼接带入交易表该组的每一条数据。完成所有这样的组的匹配。
DECLARECURSOR data_cur IS(SELECTtransaction_date AS mats_1FROM(SELECTa.BUSI_DATE AS transaction_date,sum(CASE WHEN a.ENTERED_DR <> 0 THEN a.ENTERED_DR ELSE -a.ENTERED_CR end) AS jy_moneyFROM rc_bank_transactions aWHEREa.bankaccno_sid = '111111111111'GROUP BY a.BUSI_DATE) jyINNER JOIN (SELECTtrunc(b.postdatetime) AS postdatetime,sum(b.amount) AS zj_moneyFROM issue202412_recon_zjlsb bWHEREb.wf_account ='111111111111'AND b.企业账凭证号 IS NULLGROUP BY trunc(b.postdatetime)) zjON TRUNC(jy.transaction_date) = zj.postdatetime AND jy.jy_money = zj.zj_money);mats_1 date;a_vouchers varchar2(4000);a_periods varchar2(4000);b_urids varchar2(4000);
BEGINFOR res IN data_cur LOOPmats_1 := res.mats_1;SELECT EXTRACT(XMLAGG(XMLELEMENT(e, pz, ';') ORDER BY pz),'/E/text()').GETCLOBVAL() INTO a_vouchersFROM (SELECT DISTINCT a.DOC_SEQUENCE_VALUE as pzFROM rc_bank_transactions a WHERE TRUNC(a.BUSI_DATE) = mats_1 AND a.bankaccno_sid = '111111111111');SELECT EXTRACT(XMLAGG(XMLELEMENT(e, qj, ';') ORDER BY qj),'/E/text()').GETCLOBVAL() INTO a_periodsFROM (SELECT DISTINCT a.FIN_PERIOD_NAME as qjFROM rc_bank_transactions a WHERE TRUNC(a.BUSI_DATE) = mats_1AND a.bankaccno_sid = '111111111111'); SELECT EXTRACT(XMLAGG(XMLELEMENT(e,urid, ';') ORDER BY urid),'/E/text()').GETCLOBVAL() INTO b_uridsFROM (SELECT DISTINCT b.urid as uridFROM issue202412_recon_zjlsb bWHERE trunc(b.postdatetime) = mats_1 AND b.wf_account = '111111111111'); UPDATE rc_bank_transactions a SET a.urid = b_uridsWHERE TRUNC(a.BUSI_DATE) = mats_1AND a.bankaccno_sid = '111111111111';UPDATE issue202412_recon_zjlsb b SET b.企业账凭证号 = a_vouchers,b.企业账期间 = a_periodsWHERE trunc(b.postdatetime) = mats_1 AND b.wf_account = '111111111111';END LOOP;COMMIT;
END;
场景5一对一匹配
现有一批数据,企业表和交易表要求按照账户,投保单,金额,日期匹配,将企业表的凭证号和期间带入交易表。
DECLARE
CURSOR c_update IS SELECT a.ROWID AS row_id, b.DOC_SEQUENCE_VALUE, b.PERIOD_NAME FROM rc_bank_transactions_202501 a,rc_fin_transactions_202501 b WHERE 1=1AND a.bankaccno_sid = b.bankaccno_sid AND a.REF_NUMBER = b.REF_NUMBERAND (CASE WHEN a.ENTERED_DR <> 0 THEN a.ENTERED_DR ELSE -a.ENTERED_CR end) = (CASE WHEN b.ENTERED_DR <> 0 THEN b.ENTERED_DR ELSE -b.ENTERED_CR end) AND TO_CHAR(a.BUSI_DATE, 'YYYY-MM') = TO_CHAR(b.DEFAULT_EFFECTIVE_DATE, 'YYYY-MM')AND a.DOC_SEQUENCE_VALUE IS NULL;
BEGIN FOR rec IN c_update LOOP UPDATE rc_bank_transactions_202501 SET DOC_SEQUENCE_VALUE = rec.DOC_SEQUENCE_VALUE, FIN_PERIOD_NAME = rec.PERIOD_NAME WHERE ROWID = rec.row_id; END LOOP; COMMIT;
END;
场景6 一对多匹配
现有一批数据要求交易数据按照账户,批次号,日期进行分组汇总得到汇总金额与资金表的账户,日期,金额进行匹配,
要求将交易表的拼接后的凭证号和期间带入与之匹配的资金表的数据中,同时将资金表的FUNDSFLOWCODE带入与之匹配的所以交易表的数据。
beginFOR s in (SELECTll.reqbatchno,ll.transaction_date,ss.FUNDSFLOWCODEFROM(SELECTa.reqbatchno,a.PAYSENTDATE AS transaction_date,sum(a.PAYMONEY) AS jyamountFROMissue202501_rc_batch_jylsb aWHEREa.wf_ACCOUNT = '1111111111111111111111'GROUP BYa.reqbatchno,a.PAYSENTDATE) llINNER JOIN (SELECTd.postdatetime AS postdatetime,d.amount,d.FUNDSFLOWCODEFROMissue202501_recon_zjlsb dWHEREd.wf_account = '1111111111111111111111') ss ON TRUNC(ss.postdatetime) = TRUNC(ll.transaction_date) AND ss.amount = ll.jyamount) LOOPupdate issue202501_rc_batch_jylsb
set URID = s.FUNDSFLOWCODE,资金表规则名称 = '11111更新规则1:我方账号+交易日期+单笔金额'
where 1=1
AND wf_ACCOUNT = '1111111111111111111111'
AND reqbatchno = s.reqbatchno
AND PAYSENTDATE = s.transaction_date
;UPDATE issue202501_recon_zjlsb e
SET e.规则名称= '11111更新规则1:批次号+交易提交日期+汇总金额',e.企业账凭证号 = (SELECT RTRIM(XMLAGG(XMLELEMENT(x, DOC_SEQUENCE_VALUE, ';').EXTRACT('//text()') ORDER BY DOC_SEQUENCE_VALUE).GetClobVal(), ';')FROM (SELECT DISTINCT DOC_SEQUENCE_VALUEFROM issue202501_rc_batch_jylsbWHERE URID = s.FUNDSFLOWCODE) sub),e.企业账期间 = (SELECT RTRIM(XMLAGG(XMLELEMENT(x,FIN_PERIOD_NAME, ';').EXTRACT('//text()') ORDER BY FIN_PERIOD_NAME).GetClobVal(), ';')FROM(SELECT DISTINCT FIN_PERIOD_NAMEFROM issue202501_rc_batch_jylsbWHERE URID = s.FUNDSFLOWCODE) sua)
WHERE e.FUNDSFLOWCODE = s.FUNDSFLOWCODE;end loop;commit; -- 提交所有数据
end;