简体   繁体   中英

Sql query to find the retailers who bought new product which he had not bought before

Requirement: I got 2 sets of data. Data set 1: All The retailers who purchased different items in the 3 weeks Data set 2: All The retailers who purchased different items in the 12 weeks

I would like to pick the retailers from set 1 who bought a new product which he has not bought in the 12 weeks window.

I have developed the following code which is not yielding required results. Please help

 SELECT RC.RETAILER_CD,
         RC.INV_NO,
         RC.DOC_DT,
         SUM (RC.SLS_ACT)
    FROM RANGE_CREATION RC, ACTIVITY_TXN AV
   WHERE     RC.DOC_DT > ACTIVITY_START_DT
         AND RC.DOC_DT <= ACTIVITY_CLOSURE_DT + 14
         AND RC.RETAILER_CD = AV.CHANNEL_NAME
         AND AV.TYPE = 'Range Expansion'
         AND EXISTS
                 (SELECT RC1.RETAILER_CD, RC1.INV_NO, RC1.DOC_DT
                    FROM RANGE_CREATION RC1, ACTIVITY_TXN AV1
                   WHERE     RC1.RETAILER_CD = RC.RETAILER_CD
                         AND RC1.RETAILER_CD = AV1.CHANNEL_NAME
                         AND RC1.DOC_DT > AV1.ACTIVITY_START_DT - 90
                         AND DOC_DT < ACTIVITY_START_DT
                         --AND RC1.INV_NO <> RC.INV_NO
                         AND RC1.ITM_CD <> RC.ITM_CD
                         AND AV1.TYPE = 'Range Expansion')
GROUP BY RC.RETAILER_CD, RC.INV_NO, RC.DOC_DT
  HAVING SUM (RC.SLS_ACT) > 50
ORDER BY RC.RETAILER_CD, RC.INV_NO, RC.DOC_DT;

Data Set 1:

RETAILER_CD INV_NO  DOC_DT  SLS_ACT ITM_CD
R1            1    1/4/2018    10   P1
R1            1    1/4/2018    10   P2
R1            2    31/3/2018   10   P1

Data Set 2:

RETAILER_CD INV_NO  DOC_DT  SLS_ACT ITM_CD
R1           9     1/2/2018   10    P1
R1          10     2/2/2018   11    P1
R1          11    29/1/2018   12    P3
R1          12    30/1/2018   13    P4
R1          13    31/1/2018   14    P5

Result:

RETAILER_CD INV_NO  DOC_DT  SLS_ACT ITM_CD
R1            1    1/4/2018   10     P1
R1            1    1/4/2018   10     P2

As the INV_NO 1 from Data Set-1 has got ITM_CD P2 which the retailer hasn't bought in the 90 days period, I want to pick this invoice details.

I tried to build it step-by-step for a better understanding:

1st step

Find the item, which is not found in dataset2

select dataset1.itm_cd, dataset1.inv_no, dataset2.inv_no from
    (
        select 'R1' as Retailer_cd, 1 as inv_no, 10 as sls_act, 'P1' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 1 as inv_no, 10 as sls_act, 'P2' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 2 as inv_no, 10 as sls_act, 'P1' as itm_cd from dual
    ) dataset1, -- faketable1
    (
        select 'R1' as Retailer_cd, 9 as inv_no, 10 as sls_act, 'P1' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 10 as inv_no, 11 as sls_act, 'P1' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 11 as inv_no, 12 as sls_act, 'P3' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 12 as inv_no, 13 as sls_act, 'P4' as itm_cd from dual union all
        select 'R1' as Retailer_cd, 13 as inv_no, 14 as sls_act, 'P5' as itm_cd from dual
    ) dataset2 -- faketable2
where 1=1
  AND dataset1.itm_cd = dataset2.itm_cd (+) -- Left join -> when right table not found, row is shown anyway
  AND dataset2.itm_cd is null -- only rows from dataset1 when no row in dataset2
;

Modern Left-Join

Here a modern Left-join without the fake-tables for better overview

SELECT dataset1.itm_cd, dataset1.inv_no, dataset2.inv_no
  FROM dataset1
       LEFT JOIN dataset2
           ON dataset1.itm_cd = dataset2.itm_cd AND dataset2.itm_cd IS NULL
 WHERE 1=1; -- no where-condition needed

2nd step

Find the complete order from dataset1 to the selected item.

* 2a Shorten the select

Shorten the select to the needed values

SELECT dataset1.inv_no
  FROM dataset1
       LEFT JOIN dataset2
           ON dataset1.itm_cd = dataset2.itm_cd AND dataset2.itm_cd IS NULL;

* 2b

Insert invoice-nos as table:

SELECT r.*
  FROM dataset1  r, -- this will be out output
       (SELECT distinct dataset1.inv_no -- added a distinct -> if two items in one invoice aren't bought in 90 days the inv_no will only be shown once.
          FROM dataset1, dataset2
         WHERE     1 = 1
               AND dataset1.itm_cd = dataset2.itm_cd(+)
               AND dataset2.itm_cd IS NULL) selectedItems -- this is the list of inv_nos
 WHERE selectedItems.INV_NO = dataset1.inv_no

The original request "get retailers that bought an item in set1 they didn't buy in set2" is easy peasy:

select distinct retailer_cd
from set1
where (retailer_cd, itm_cd) not in (select retailer_cd, itm_cd from set2);

But now you have added expected results and want the complete invoices where such purchases occur, instead of merely listing the retailers. One way is to get the purchase first and then get the whole invoice in the next step with another IN clause:

select *
from set1
where (retailer_cd, inv_no) in
(
  select retailer_cd, inv_no
  from set1
  where (retailer_cd, itm_cd) not in (select retailer_cd, itm_cd from set2)
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM