You Asked
Hi Tom,
Is this possible to do from a SQL-query.
I have a set of numbers that need to be converted from one currency to another. The sum of the converted values differ slightly from the original number and the difference - as long it is within a limit- should be added to one of the items making the sum. If the limit -lets say .50 is exceeded then an error should be raised.
The example below is a real-life example where the converted amounts should total 23 727.86 but thanks to rounding differences they total 23 727.85. Now the 0.01 should be placed in one of the items below, preferably to the largest/smallest one depending on the sign of the total.
Thank you for your time,
Cheers
Kari
==== EXAMPLE ====
CREATE TABLE T (ORIG NUMBER(10,2), CONV NUMBER(10,2));
INSERT INTO T (ORIG, CONV) VALUES (-90.59 , -67.69);
INSERT INTO T (ORIG, CONV) VALUES (4174.00 , 3118.88);
INSERT INTO T (ORIG, CONV) VALUES (4809.00 , 3593.36);
INSERT INTO T (ORIG, CONV) VALUES (198.00 , 147.95);
INSERT INTO T (ORIG, CONV) VALUES (-198.00 , -147.95);
INSERT INTO T (ORIG, CONV) VALUES (-5.00 , -3.74);
INSERT INTO T (ORIG, CONV) VALUES (87.03 , 65.03);
INSERT INTO T (ORIG, CONV) VALUES (8.00 , 5.98);
INSERT INTO T (ORIG, CONV) VALUES (-16.00 , -11.96);'
INSERT INTO T (ORIG, CONV) VALUES (37.00 , 27.65);
INSERT INTO T (ORIG, CONV) VALUES (1.38 , 1.03);
INSERT INTO T (ORIG, CONV) VALUES (22543.62 , 16844.97);
INSERT INTO T (ORIG, CONV) VALUES (-12.17 , -9.09);
INSERT INTO T (ORIG, CONV) VALUES (-10.01 , -7.48);
INSERT INTO T (ORIG, CONV) VALUES (174.06 , 130.06);
INSERT INTO T (ORIG, CONV) VALUES (-3.34 , -2.5);
INSERT INTO T (ORIG, CONV) VALUES (58.02 , 43.35);
The rate used is 1,338300. The 23 727.86 is a given figure (by the bank, resulting from converting the sum(orig) using the rate [31755/1.338300]. However, the bank doesn't provide the split for each line so that has to be calculated.
and Tom said...
we can do this with analytics rather easily....
getting the "total" diff is pretty easy:
ops$tkyte@ORA9IR2> select orig,
2 orig*1.33830,
3 round(orig*1.33830,2),
4 sum(orig*1.33830) over () - sum(round(orig*1.33830,2)) over () diff
5 from t;
ORIG ORIG*1.33830 ROUND(ORIG*1.33830,2) DIFF
---------- ------------ --------------------- ----------
-90.59 -121.2366 -121.24 .0122
4174 5586.0642 5586.06 .0122
4809 6435.8847 6435.88 .0122
198 264.9834 264.98 .0122
-198 -264.9834 -264.98 .0122
-5 -6.6915 -6.69 .0122
87.03 116.472249 116.47 .0122
8 10.7064 10.71 .0122
1.38 1.846854 1.85 .0122
22543.62 30170.1266 30170.13 .0122
-12.17 -16.287111 -16.29 .0122
-10.01 -13.396383 -13.4 .0122
174.06 232.944498 232.94 .0122
-3.34 -4.469922 -4.47 .0122
58.02 77.648166 77.65 .0122
15 rows selected.
Here, I am finding the "smallest" and "largest" and tagging each with rn1=1 and rn2=1 repectively. Then, we use a case to see if we want to add the negative difference to the smallest or the positive difference to the largest (assuming that is what you want -- else change the logic))
the last columns are just for "debug" and the 1/0 one is to fail the query in the event the difference exceeds your threshold...
ops$tkyte@ORA9IR2> column subed format a15
ops$tkyte@ORA9IR2> column added format a15
ops$tkyte@ORA9IR2> select orig,
2 round(
3 new+(case when rn1=1 and diff < 0 then diff else 0 end)
4 +(case when rn2=1 and diff > 0 then diff else 0 end),2 ) new,
5 case when abs(diff) > 0.50 then 1/0 end err,
6 (case when rn1=1 and diff < 0 then diff||','||new end) subed,
7 (case when rn2=1 and diff > 0 then diff||','||new end) added
8 from (
9 select orig,
10 orig*1.33830,
11 round(orig*1.33830,2) new,
12 sum(orig*1.33830) over () - sum(round(orig*1.33830,2)) over () diff,
13 row_number() over (order by orig) rn1,
14 row_number() over (order by orig desc) rn2
15 from t );
ORIG NEW ERR SUBED ADDED
---------- ---------- ---------- --------------- ---------------
22543.62 30170.14 .0122,30170.13
4809 6435.88
4174 5586.06
198 264.98
174.06 232.94
87.03 116.47
58.02 77.65
8 10.71
1.38 1.85
-3.34 -4.47
-5 -6.69
-10.01 -13.4
-12.17 -16.29
-90.59 -121.24
-198 -264.98
15 rows selected.
Rating
(5 ratings)
Is this answer out of date? If it is, please let us know via a Comment