У меня есть остатки на счетах, подобные этому
acc_no balance balance_date
account1 5000 2020-01-01
account1 6000 2020-01-05
account2 3000 2020-01-01
account1 3500 2020-01-08
account2 7500 2020-01-15
Эффективный баланс за любой день без ввода баланса равен последнему балансу. Например, баланс счета 1 на 2,3,4 января составляет 5000 et c.
Я хотел бы получить среднесуточное значение, начальное и конечное сальдо из этих данных за любой период. Я пришел к следующему запросу, и он работает, но он занимает полчаса, когда я запускаю его с полным набором данных. Мой подход правильный или есть более эффективный метод?
WITH cte_period
AS (
SELECT '2020-01-01' date_from
,'2020-01-31' date_to
FROM dual
)
,cte_calendar
AS (
SELECT rownum
,(
SELECT to_date(date_from, 'YYYY-MM-DD')
FROM cte_period
) + rownum - 1 AS balance_day
FROM dual connect BY rownum <= (
SELECT to_date(date_to, 'YYYY-MM-DD')
FROM cte_period
) - (
SELECT to_date(date_from, 'YYYY-MM-DD')
FROM cte_period
) + 1
)
,cte_balances
AS (
SELECT 'account1' acc_no
,5000 balance
,to_date('2020-01-01', 'YYYY-MM-DD') sys_date
FROM dual
UNION ALL
SELECT 'account1'
,6000
,to_date('2020-01-05', 'YYYY-MM-DD')
FROM dual
UNION ALL
SELECT 'account2'
,3000
,to_date('2020-01-01', 'YYYY-MM-DD')
FROM dual
UNION ALL
SELECT 'account1'
,3500
,to_date('2020-01-08', 'YYYY-MM-DD')
FROM dual
UNION ALL
SELECT 'account2'
,7500
,to_date('2020-01-15', 'YYYY-MM-DD')
FROM dual
)
,cte_accounts
AS (
SELECT DISTINCT acc_no
FROM cte_balances
)
SELECT t.acc_no
,(
SELECT eff_bal
FROM (
SELECT cal.balance_day
,acc_nos.acc_no
,(
SELECT balance
FROM cte_balances bal
WHERE bal.sys_date <= cal.balance_day
AND acc_nos.acc_no = bal.acc_no
ORDER BY bal.sys_date DESC FETCH first 1 row ONLY
) eff_bal
FROM cte_calendar cal
CROSS JOIN cte_accounts acc_nos
) t1
WHERE balance_day = (
SELECT to_date(date_from, 'YYYY-MM-DD')
FROM cte_period
)
AND t.acc_no = t1.acc_no
) opening_bal
,(
SELECT eff_bal
FROM (
SELECT cal.balance_day
,acc_nos.acc_no
,(
SELECT balance
FROM cte_balances bal
WHERE bal.sys_date <= cal.balance_day
AND acc_nos.acc_no = bal.acc_no
ORDER BY bal.sys_date DESC FETCH first 1 row ONLY
) eff_bal
FROM cte_calendar cal
CROSS JOIN cte_accounts acc_nos
) t1
WHERE balance_day = (
SELECT to_date(date_to, 'YYYY-MM-DD')
FROM cte_period
)
AND t.acc_no = t1.acc_no
) closing_bal
,round(avg(eff_bal), 2) avg_bal
FROM (
SELECT cal.balance_day
,acc_nos.acc_no
,(
SELECT balance
FROM cte_balances bal
WHERE bal.sys_date <= cal.balance_day
AND acc_nos.acc_no = bal.acc_no
ORDER BY bal.sys_date DESC FETCH first 1 row ONLY
) eff_bal
FROM cte_calendar cal
CROSS JOIN cte_accounts acc_nos
) t
GROUP BY acc_no
order by acc_no
Ожидаемый результат ACC_NO OPENING_BAL CLOSING_BAL AVG_BAL account1 5000 3500 3935.48 account2 3000 7500 5467.74