Here's a little puzzle that's cooking my brains. What can be done to solve?

Guys
Insightful wisdoms herein, the following small problem has landed with me.
Suppose I run a bank and there is a big table of financial transactions. Every credit card therein gains points for every dollar they spend. Keep it simple, 1 point for $1.
A third party company sells gifts in exchange for the points, and we send a file every night of the number of points that must be added to our member's account over at their store.. Joe Schmoe spent $200 today, add 200 points to his account. This part is easy
Problem comes when something is refunded with us (the "bank"), the points balance at the third party CANNOT be decremented (dumb, I know), so that $1000 purchase of a TV netted Joe 1000 points even though he took the TV back a week later and got his money back. Refunds can occur at any time, and you cannot assume that an item will be refunded properly between two runs of the report that prepares the points file (i.e. before sending over the points, you can't add up all the spends, add up all the refunds and send the difference as the points, because some refunds won't have happened yet).
The proposal is that as a result, Joe Schmoe's card should go into "points debt" of 1000 points, and we only start sending new points to the third party once Joe has spent more than $1000 again.. So points updates should be paused and if Joe spends over the next 4 days:
500
300
150
90
then the last transaction for $90 on day 4 clears his outstanding points debt of -50 points and we should send 40 points over to the third party company
If such a problem could be entirely solved within a SELECT, then that's cool but I have development ability on the reports system that runs the SQLs so I can add options to run other query types after, or add support for returning a cursor and implementing this in PL/SQL with lots more advanced logic
Regards
cj

I am unsure of the efficiency of this and it is hard to tell if this is what you need without example data and output, but I think this is what you are looking for.
Suppose we have sample data like this (where negative numbers are normal transactions - debits, and positive numbers are refunds or credits back to the account.
with t as (
select 1 id, sysdate - 5 dte, -1000 amount from dual UNION ALL
select 1, sysdate - 4, -500 from dual UNION ALL
select 1, sysdate - 3, 500 from dual UNION ALL
select 1, sysdate - 2, -250 from dual UNION ALL
select 1, sysdate - 1, -300 from dual)
select * from t;
ID                     DTE                       AMOUNT                
1                      28-FEB-09                 -1000                 
1                      01-MAR-09                 -500                  
1                      02-MAR-09                 500                   
1                      03-MAR-09                 -250                  
1                      04-MAR-09                 -300                  
5 rows selectedFirst step is to get the actual number of points the customer should have at each date.
with t as (
select 1 id, sysdate - 5 dte, -1000 amount from dual UNION ALL
select 1, sysdate - 4, -500 from dual UNION ALL
select 1, sysdate - 3, 500 from dual UNION ALL
select 1, sysdate - 2, -250 from dual UNION ALL
select 1, sysdate - 1, -300 from dual)
select t.*,
       sum(-amount) over (partition by id order by dte rows unbounded preceding) actual
from t;
ID                     DTE                       AMOUNT                 ACTUAL                
1                      28-FEB-09                 -1000                  1000                  
1                      01-MAR-09                 -500                   1500                  
1                      02-MAR-09                 500                    1000                  
1                      03-MAR-09                 -250                   1250                  
1                      04-MAR-09                 -300                   1550                  
5 rows selectedThe next step is slightly more tricky - I am going to use the max() analytic function combined with a sliding window so we can eliminate the reduction in the actual. See below:
with t as (
select 1 id, sysdate - 5 dte, -1000 amount from dual UNION ALL
select 1, sysdate - 4, -500 from dual UNION ALL
select 1, sysdate - 3, 500 from dual UNION ALL
select 1, sysdate - 2, -250 from dual UNION ALL
select 1, sysdate - 1, -300 from dual)
select b.*,
       max(actual) over (partition by id order by dte rows unbounded preceding) curr
from (select t.*,
             sum(-amount) over (partition by id order by dte rows unbounded preceding) actual
      from t) b;
ID                     DTE                       AMOUNT                 ACTUAL                 CURR                  
1                      28-FEB-09                 -1000                  1000                   1000                  
1                      01-MAR-09                 -500                   1500                   1500                  
1                      02-MAR-09                 500                    1000                   1500                  
1                      03-MAR-09                 -250                   1250                   1500                  
1                      04-MAR-09                 -300                   1550                   1550                  
5 rows selectedSo as you can see, this gives the total number of points at each date that should have been sent to the customer.
And so finally, we use lag on that result and find the difference (using NVL to handle the first case):
with t as (
select 1 id, sysdate - 5 dte, -1000 amount from dual UNION ALL
select 1, sysdate - 4, -500 from dual UNION ALL
select 1, sysdate - 3, 500 from dual UNION ALL
select 1, sysdate - 2, -250 from dual UNION ALL
select 1, sysdate - 1, -300 from dual)
select id,
       dte,
       amount,
       curr - nvl(lag(curr) over (partition by id order by dte),0) diff
from (select b.*,
             max(actual) over (partition by id order by dte rows unbounded preceding) curr
      from (select t.*,
                   sum(-amount) over (partition by id order by dte rows unbounded preceding) actual
            from t) b) d;
ID                     DTE                       AMOUNT                 DIFF                  
1                      28-FEB-09                 -1000                  1000                  
1                      01-MAR-09                 -500                   500                   
1                      02-MAR-09                 500                    0                     
1                      03-MAR-09                 -250                   0                     
1                      04-MAR-09                 -300                   50                    
5 rows selectedAnd that should give the points to send at each date.

Similar Messages

Maybe you are looking for

  • IMac 24" disaster

    Here's my disappointing story: I bought one of the 24" iMacs the day it came out. About 10 days later I received it and one of the first things I did was install windows XP. I followed the bootcamp/xp installation procedure exactly but once through t

  • Story - not able to log in and retrieve written work

    I have cs 5.5 production premium and have been using story for a lot of written work and script writing over the summer. I didnt log in for a month or so and now it says i need to upgrade and i click the link and it just takes me to the adobe product

  • File transfter issue - Lenovo S860

    Hello Geeks, I have detected one silly but quite serious issue in my lenovo S860 smartphone. Once a while I was trasfering a music file , I have chosen send via 'WhatsApp' option and marked on 'Always'. Now problem is whenever i want  to trasfter any

  • [SOLVED} linux-dvb-apps initial scan files

    Anyone know where to find the linux-dvb-apps initial scan files. They used to be under /usr/share/dvb/, but the latest linux-dvb-apps package just lists contents in /usr/share/dvb/av7110_loadkeys/ Failing that has anyone got a decent scan file for uk

  • The printer that comes up when i hit print is not my default printer

    I can print from my documents or desktop but when I open firefox and try to print it opens a print window with a fax as my printer. I can hit the down arrow and see my printer but it will not allow me to select it. My default is the correct printer