tags:

views:

171

answers:

3

Here is my situation:

I have one table that contains a list of drugs sold containing the NDC (an identifier), quantity sold, and whether the drug is a brand name or generic. I have another table that contains the prescription numbers, dates, and NDCs.

I need to generate a list of the most recent 4 prescription numbers for the top 50 generic drugs and the top 50 Brand name drugs.

Simplified example:

Drug_list:
NDC   QTY      Type
123   50       Generic
125   47       Brand
128   34       Generic
...
549   1        Brand
294   1        Generic

Claims_list:
NDC  RX_num  Date
123  1234    20081027
123  4194    20090517
594  12598   20091012

How would I write a join to generate a list of

NDC RX1, RX2, RX3, RX4

where NDC are the 50 most common 'Brand' NDCs, and the following RXs are the RX numbers of the most recent claims?

~~~~~~~

So far I've got this:

select t.ndc, cl.rx, cl.date from (
select * from (
select * from (
select * from drug_list where brand = 'Generic')
order by qty)
where rownum < 51) t
join claims_list cl on cl.ndc = t.ndc
order by t.ndc, cl.date;

Which gets me part of the way there. From there, how do I trim it down to only 4 results per NDC? And, is it possible to get it in the following from:

NDC, RX1, RX2, RX3, RX4

If I have to report it as:

NDC1, RX1
NDC1, RX2
NDC1, RX3
NDC1, RX4
NDC2, RX1
NDC2, RX2
NDC2, RX3
NDC2, RX4
NDC3, RX1
... etc

but I would prefer to have it on one line.

~~~~ (as requested by a comment: create table statements for example tables):

create table drug_list
(NDC varchar2(15), QTY number, type varchar2(10));

create table claims_list
(NDC varchar2(15), RX_num varchar2(20), "date" date);
+1  A: 

You can use a combination of Analytics (if you are on a recent enough version of Oracle) and a Pivot Table to do it. This should work with your dataset.

select ndc,
       max(decode(rn, 1, rx_num, null)) rx1,
       max(decode(rn, 2, rx_num, null)) rx2,
       max(decode(rn, 3, rx_num, null)) rx3,
       max(decode(rn, 4, rx_num, null)) rx4
  from (select *
          from (select claims_list.ndc,
                       claims_list.rx_num,
                       row_number() over (partition by claims_list.ndc order by claims_list.date desc) rn
                  from claims_list,
                       (select * 
                          from (select *
                                  from drug_list
                                 where type = 'Generic'
                                order by qty desc
                               )
                         where rownum < 51
                       ) drug_list
                 where drug_list.ndc = claims_list.ndc
               )
         where rn < 5
        order by ndc, rn
       )
group by ndc;

The inner query uses analytics to pull the most recent 4 rx numbers for each drug based on the claim date. Then we use a pivot to take it from 4 lines per drug to one line with 4 columns.

Dougman
That did the trick! Thanks
David Oneill
A: 

Making some assumptions, and I'm not sure the exact Oracle syntax....but what about:

SELECT
    "ndc" as NDC,
    ( SELECT "rx_num" from "rx" WHERE "ndc"="drug_list"."ndc" ORDER BY "date" DESC LIMIT 1 OFFSET 0 ) as RX1,
    ( SELECT "rx_num" from "rx" WHERE "ndc"="drug_list"."ndc" ORDER BY "date" DESC LIMIT 1 OFFSET 1 ) as RX2,
    ( SELECT "rx_num" from "rx" WHERE "ndc"="drug_list"."ndc" ORDER BY "date" DESC LIMIT 1 OFFSET 2 ) as RX3,
    ( SELECT "rx_num" from "rx" WHERE "ndc"="drug_list"."ndc" ORDER BY "date" DESC LIMIT 1 OFFSET 3 ) as RX4
FROM "drug_list"
ORDER BY qty ASC
LIMIT 4

NDC | RX1 | RX2 | RX3 | RX4
123   2332  2342  2346  7776
Kevin Peno
limit and offset didn't seem to work for me. Are there oracle equivs?
David Oneill
I found this when searching for an Oracle equiv. http://rifers.org/blogs/gbevin/2004/1/25/limit_and_offset_in_oracle
Kevin Peno
Also found this: SELECT column FROM table WHERE ROWNUM BETWEEN 10 AND 20, but I'm not sure how to translate it to LIMIT 1 OFFSET 1. Would it be SELECT column FROM table WHERE ROWNUM BETWEEN 0 AND 1 and then increment 0 to 1 and 1 to 2, etc for each extra query?
Kevin Peno
@Kevin: Ok. This is more or less the same solution that Doug suggested above. @Kevin: just calling between on rownum without setting it up separately doesn't work. IE if you ever ask a query to not return rownum = 1, you won't get ANY results.
David Oneill
I'm sorry this didn't work for you. It is basic syntax supported in SQL-92 compliant systems. So I, falsely, assumed it would work for you.
Kevin Peno
A: 

This would get you each one on a separate line:

SELECT
  `cl`.`ndc`,
  `cl`.`rx_num`
FROM `claims_list` AS `cl`
WHERE `cl`.`ndc` IN
  (
    SELECT `dl`.`ndc` FROM `drug_list` AS `dl`
    WHERE `dl`.`type` = 'Generic'
    ORDER BY `dl`.`qty` DESC
    LIMIT 50
  )
ORDER BY `cl`.`date` DESC
LIMIT 4

Then run the results through a filter in the calling script to group them together.

Oz