views:

2216

answers:

1

I have a table of transactions which will occasionally have duplicate entries. If/When an admin finds these duplicate entries, they will reverse the transactions, therefore creating a negative value (but the original duplicate still remains due to regulatory requirements). I'd like to create a SQL query (and use Crystal Reports) to make a report for the admins to easily find duplicate transactions. Due to the mass quantity of transactions, I'd like to make it easier for them by disregarding transactions that they have already reversed.

Here's an example of what I'd like to do:

Transaction Date ; Transaction Qty ; Transaction Value ; Reversal

1/1/08    ; 14    ;    70.00    ; N
1/1/08    ; 14    ;    70.00    ; N
1/1/08    ; -14   ;    -70.00   ; Y
2/1/08    ; 17    ;    89.00    ; N
2/15/08   ; 18    ;    95.00    ; N
2/15/08   ; 18    ;    95.00    ; N
3/1/08    ; 11    ;    54.00    ; N
3/1/08    ; -11   ;    -54.00   ; Y
3/1/08    ; 11    ;    54.00    ; N
3/1/08    ; 11    ;    54.00    ; N
3/1/08    ; 11    ;    54.00    ; N

Ideally, if I ran my "desired" query on the table above, I would receive the following result:

Transaction Date ; Transaction Qty ; Transaction Value ; Count

2/15/08    ; 18    ;    95.00    ; 2
3/1/08     ; 11    ;    54.00    ; 3

Does that make sense? I've already figured out how to write the query to give me a count of duplicates, but I can't figure out how to exclude duplicate records which have been "backed out" already. Any help would be greatly appreciated!

+4  A: 

How about:

select dt, abs(qty), abs(val),
       sum(case when reversal='Y' then -1 else 1 end) as count
from transactions
group by dt, abs(qty), abs(val)
having sum(case when reversal='Y' then -1 else 1 end) > 1;

I have just tested it in Oracle and it works:

create table transactions
( dt date
, qty number
, val number
, reversal varchar2(1)
);

insert into transactions values (to_date('1/1/08','mm/dd/yy')    , 14    ,    70.00    , 'N');
insert into transactions values (to_date('1/1/08','mm/dd/yy')    , 14    ,    70.00    , 'N');
insert into transactions values (to_date('1/1/08','mm/dd/yy')    , -14   ,    -70.00   , 'Y');
insert into transactions values (to_date('2/1/08','mm/dd/yy')    , 17    ,    89.00    , 'N');
insert into transactions values (to_date('2/15/08','mm/dd/yy')   , 18    ,    95.00    , 'N');
insert into transactions values (to_date('2/15/08','mm/dd/yy')   , 18    ,    95.00    , 'N');
insert into transactions values (to_date('3/1/08','mm/dd/yy')    , 11    ,    54.00    , 'N');
insert into transactions values (to_date('3/1/08','mm/dd/yy')    , -11   ,    -54.00   , 'Y');
insert into transactions values (to_date('3/1/08','mm/dd/yy')    , 11    ,    54.00    , 'N');
insert into transactions values (to_date('3/1/08','mm/dd/yy')    , 11    ,    54.00    , 'N');
insert into transactions values (to_date('3/1/08','mm/dd/yy')    , 11    ,    54.00    , 'N');

SQL> select dt, abs(qty), abs(val),
  2         sum(case when reversal='Y' then -1 else 1 end) as count
  3  from transactions
  4  group by dt, abs(qty), abs(val)
  5  having sum(case when reversal='Y' then -1 else 1 end) > 1;

DT            ABS(QTY)   ABS(VAL)      COUNT
----------- ---------- ---------- ----------
15-FEB-2008         18         95          2
01-MAR-2008         11         54          3
Tony Andrews
Thanks for your comment on my post; my query was way off and I've removed it. Cheers
Nahom Tijnam
Wow, this is exactly what I needed.... It works perfectly! Thank you SO much for saving me from a headache.You must be pretty good to come up with that solution so quickly. Thanks again!
Leslie
Looks good. Unless a reversal has a mistake (doesn't have the correct quantity and value), should do the trick.
Jonathan Leffler
Thanks. Re Jonathan's point: very true. I have worked on a system like this where the reveral records had a reversed_transaction_id column so that you could pair up original records with the corresponding reversals.
Tony Andrews