Есть список задач. У каждой задачи есть список объектов, для которых рассчитываются некоторые начисления.
По окончанию месяца нужно выбрать все задачи этого месяца, просуммировать начисления, округлить вниз до целых.
Если сумма получилась нулевая, то объект пропускается.
После окончания обработки у объектов и задач меняется статус (в зависимости от того, было проведено начисление или пропущено).
Сделал я примерно таким образом.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
PROCEDURE CA_REFUND(p_accident NUMBER, p_date DATE, p_period DATE, res OUT recResultOut) AS
CURSOR cur_rcpt (filter_accident NUMBER, filter_date DATE, filter_period DATE) IS
select
case
when filter_accident is not null then 'инцидент ' || filter_accident
when filter_date is not null then to_char(filter_date, 'DD.MM.YYYY')
when filter_period is not null then to_char(filter_period, 'FMmonth YYYY', 'NLS_DATE_LANGUAGE=russian')
end as "MODE"
, C.CUSTOMER_ID as CLIENT
, RS.IDS
, RS.INC
, RS.QTY
, RS.CNT
, RS.SUM
from (
select RS.ACCOUNT_ID
, wm_concat(RS.ACCIDENT_ID) as IDS
, count(distinct RS.ACCIDENT_ID) as INC
, count(distinct RS.SERVICE_ID) as QTY
, count(*) as CNT
, trunc(sum(RS.RECALC)) as SUM
from (
select ...
from ...
where ...
and (filter_accident is null or (AL.ACCIDENT_ID = filter_accident) )
and (filter_date is null or (AL.MOMENT_END >= filter_date and AL.MOMENT_END < (filter_date+1)) )
and (filter_period is null or (AL.MOMENT_END >= filter_period and AL.MOMENT_END < add_months(filter_period, 1)) )
) RS
group by RS.ACCOUNT_ID
) RS
join CUSTOMERS C on (...)
;
rec_rcpt cur_rcpt%ROWTYPE;
BEGIN
...
open cur_rcpt(p_accident, trunc(p_date), trunc(p_period, 'MM'));
loop
fetch cur_rcpt into rec_rcpt;
exit when cur_rcpt%NOTFOUND;
v_num := v_num + 1;
if (rec_rcpt.SUM = 0) then
v_skip := v_skip + 1;
merge into ACCIDENT_RCPT T
using (
select AR.ACCIDENT_ID, AR.CLIENT
from ACCIDENT_RCPT AR
join (select distinct regexp_substr(rec_rcpt.IDS, '[^,]+', 1, level) ACCIDENT_ID from dual connect by level <= rec_rcpt.CNT) IDS on (IDS.ACCIDENT_ID = AR.ACCIDENT_ID)
where AR.CUSTOMER_ID = rec_rcpt.CLIENT
) RS on (RS.ACCIDENT_ID = T.ACCIDENT_ID and RS.CLIENT = T.CLIENT)
when matched then update set MOMENT = sysdate, STATUS = -1
;
else
v_cnt := v_cnt + 1;
v_sum := v_sum + rec_rcpt.SUM;
merge into ACCIDENT_RCPT T
using (
select AR.ACCIDENT_ID, AR.CLIENT
from ACCIDENT_RCPT AR
join (select distinct regexp_substr(rec_rcpt.IDS, '[^,]+', 1, level) ACCIDENT_ID from dual connect by level <= rec_rcpt.CNT) IDS on (IDS.ACCIDENT_ID = AR.ACCIDENT_ID)
where AR.CUSTOMER_ID = rec_rcpt.CLIENT
) RS on (RS.ACCIDENT_ID = T.ACCIDENT_ID and RS.CLIENT = T.CLIENT)
when matched then update set MOMENT = sysdate, STATUS = 4
;
end if;
end loop;
close cur_rcpt;
...
END;
Поскольку в списке у меня только числа, разделены они запятой и количество чисел мне известно, то удалось разбить текст на строки с помощью connecy by (regexp_substr).
А можно ли использовать сразу OdciNumberList, чтобы передавать ему не список значений, а одну строку?