Vannak részösszegeink, amelyeket eFt-ra alakítunk osztással és kerekítéssel. Ám ezt oly módon kéne megtennünk, hogy a kerekítetlen részösszegek szummája megegyezzen a kerekítettekével. Minden korrigált részösszeg eltérése az eredetitől legyen <1. Hogyan tudjuk ezt megoldani SQL-ben (Postgres)?
with
-- tesztadatok
testdata(category, amt) as (
values
('alma', 234555),
('banán', 67777),
('citrom', 9888),
('dinnye', 999666)
),
-- a gyakorlatban aggregálnánk az adatainkat
testdata_aggr as (
select
-- ennek most nincs valódi szerepe
category,
-- ez viszont lényeges: eFt összegeket akarunk látni
sum(amt) / 1000.0 as amt_sum
from testdata
group by category
),
-- szükségünk van néhány számított értékre
testdata_aggr_calc as (
select
category,
amt_sum,
-- a törtrész szerinti sorrend függ a korrekció irányától
case
when corr_dir < 0 then
frac_desc_rn
else
frac_asc_rn
end frac_rn,
corr_dir,
corr_lim
from (
select
category,
amt_sum,
frac_desc_rn,
frac_asc_rn,
-- a korrekció iránya: 1: felfelé; -1: lefelé
case
when total_original_sum - total_rounded_sum >= 0 then
1
else
-1
end as corr_dir,
-- korrekciós limit: hány értéket kell a többitől eltérően kerekíteni
abs(total_original_sum - total_rounded_sum) as corr_lim
from (
select
category,
amt_sum,
-- törtrész szerint csökkenő sorszám
row_number() over (order by frac desc) as frac_desc_rn,
-- törtrész szerint növekvő sorszám
row_number() over (order by frac asc) as frac_asc_rn,
-- az eredeti értékek összege kerekítve
round(sum(amt_sum) over ()) as total_original_sum,
-- a kerekített értékek összege
sum(round(amt_sum)) over () as total_rounded_sum
from (
select
category,
-- levágjuk az osztás után keletkezett fölös 0-kat
round(amt_sum, 3) as amt_sum,
-- törtrész
amt_sum - floor(amt_sum) as frac
from testdata_aggr
) t1
) t2
) t3
)
select
frac_rn,
category,
-- az eredeti részösszeg (eFt kerekítés nélkül)
amt_sum,
-- speciálisan kerekített részösszeg
case
when frac_rn <= corr_lim then
case
when corr_dir < 0 then
floor(amt_sum)
else
ceil(amt_sum)
end
else
round(amt_sum)
end as amt_sum_corr
from testdata_aggr_calc
order by frac_rn
;
Jelen esetben az eredeti és a kerekített értékek szummáinak különbsége -1, ezért az 1. legnagyobb törtrészű értéket lefelé kerekítjük.
frac_rn | category | amt_sum | amt_sum_corr
---------+----------+---------+--------------
1 | citrom | 9.888 | 9
2 | banán | 67.777 | 68
3 | dinnye | 999.666 | 1000
4 | alma | 234.555 | 235