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