简体   繁体   English

Oracle SQL查询将一行数据与28天后的数据进行比较

[英]Oracle SQL query to compare data of a row with that of 28 days back

I have a table TableA like below: 我有一个表TableA如下:

WEEK |COL1 |COL2 |COL3 |COL4 |COL5 |CLOSING_BALANCE |REPORT_DATE
-----|-----|-----|-----|-----|-----|----------------|-----------
----------------------------------------------------------------
WEEK_1|123|Y|1|123|Y|100|19/07/2016
WEEK_5|123|Y|1|123|Y|300|16/08/2016
WEEK_9|123|Y|1|123|Y|400|13/09/2016
WEEK_5|345|N|2|859|N|658|16/08/2016
WEEK_1|456|N|5|795|N|50|19/07/2016
WEEK_13|456|N|5|795|N|230|11/10/2016
WEEK_9|456|N|5|795|N|120|13/09/2016
WEEK_1|567|Y|4|567|N|111|19/07/2016
WEEK_13|567|Y|4|567|N|222|11/10/2016
WEEK_1|678|N|2|564|Y|900|19/07/2016
WEEK_9|789|N|3|458|Y|200|13/09/2016

Each row needs to be compared with 28days (report_date-28) back data for the same combination of COL1, COL2, COL3, COL4 and COL5. 需要将每行与28天(report_date-28)的数据进行比较,以获得COL1,COL2,COL3,COL4和COL5的相同组合。

Let's assume I am comparing week_5 with week_1 我们假设我将week_5与week_1进行比较

Case1: Present in current row and present 28days back as well. 案例1:出现在当前行并且还有28天回来。

Say for week_5 I get a matching combination of COL1, COL2, COL3, COL4 and COL5 28 days back ie in week_1. 比如说周五我在28天后得到了COL1,COL2,COL3,COL4和COL5的匹配组合,即在第1周。 Now in the output I want 1 single row for these two rows, with week_1 closing_base as prev_closing_base and week_5 closing_base as current_closing base. 现在在输出中我想要这两行的单行,其中week_1 closing_base为prev_closing_base,week_5 closing_base为current_closing base。

Example: week_5/123 week_1/123 示例:week_5 / 123 week_1 / 123

Case2: Present 28days back but missing in current 案例2:现在28天回来,但目前缺席

If a combination is present in say week_1 but missing in week_5. 如果在week_1中存在组合但在week_5中缺少组合。 I want prev_closing_base as week_1's closing_base and current_closing base as 0. Example: week_1/678 我希望prev_closing_base为week_1的closing_base和current_closing base为0.例如:week_1 / 678

Case3: Present in current row but missing 28 days back 案例3:出现在当前行但缺少28天

If a combination is present in say week_5 but missing in week_1. 如果在week_5中存在组合但在week_1中缺少组合。 I want prev_closing_base as 0 and current_closing base as closing_base of week_5. 我想将prev_closing_base设置为0,将current_closing base设置为week_5的closing_base。 Example: week5/345 & week_9/789 示例:week5 / 345&week_9 / 789

The output should be as below:- 输出应如下: -

WEEK |  COL1 |  COL2 | COL3 | COL4 | COL5   | CLOSING_BALANCE_28DAYS_AGO | CURR_CLOSING_BALANCE
----------------------------------------------------------------------------------------------
WEEK_1 |456|N|5|795|N|50 |0
WEEK_5 |123|Y|1|123|Y|100|300
WEEK_5 |345|N|2|859|N|0  |658
WEEK_1 |678|N|2|564|Y|900|0
WEEK_9 |789|N|3|458|Y|0  |200
WEEK_9 |123|Y|1|123|Y|300|400
WEEK_13|456|N|5|795|N|120|230
WEEK_1 |567|Y|4|567|N|111|0
WEEK_13|567|Y|4|567|N|0  |222

I tried to do full outer join on the same table. 我试图在同一个表上进行完全外连接。 But this is not working . 但这不起作用。 Its giving duplicate rows. 它给出了重复的行。

        select nvl (curr.WEEK, prev.WEEK) WEEK,
               nvl (curr.COL1, prev.COL1) COL1,
               nvl (curr.COL2, prev.COL2) COL2,
               nvl (curr.COL3, prev.COL3) COL3,   
               nvl (curr.COL4, prev.COL4) COL4,
               nvl (curr.COL5, prev.COL5) COL5,
               nvl (prev.CLOSING_BALANCE, 0) PREV_CLOSING_BALANCE_28DAYS_AGO,
               nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
          from TableA curr
               full outer join TableA prev
                  on curr.report_date - 28 = prev.report_date
                     and curr.COL1 = prev.COL1
                     and curr.COL3 = prev.COL3
                     and curr.COL4 = prev.COL4
                     and curr.COL2 = prev.COL2
                     and curr.COL5 = prev.COL5;

Left outer join does not seem to work as well 左外连接似乎也不起作用

    select nvl (curr.year_week, prev.year_week) year_week,
           nvl (curr.COL1, prev.COL1) COL1,
           nvl (curr.COL2, prev.COL2) COL2,
           nvl (curr.COL3, prev.COL3) COL3,   
           nvl (curr.COL4, prev.COL4) COL4,
           nvl (curr.COL5, prev.COL5) COL5,
           nvl (prev.CLOSING_BALANCE, 0) PREV_CLOSING_BALANCE_28DAYS_AGO,
           nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
      from TableA curr
           left outer join TableA prev
              on curr.edw_report_date - 28 = prev.edw_report_date
                 and curr.COL1 = prev.COL1
                 and curr.COL3 = prev.COL3
                 and curr.COL4 = prev.COL4
                 and curr.COL2 = prev.COL2
                 and curr.COL5 = prev.COL5; 

Output from left outer join:- 左外连接的输出: -

YEAR_WEEK|MOB_PROMOTION_KEY|BTM_EMPLOYEE_FLG|SIM_ACTIVATION_STATUS_KEY|BTM_HANDSET_KEY|BTM_ADDON_XSPEED4G_FLG|CLOSING_BASE_28DAYS_AGO|CURR_CLOSING_BASE
------------------------------------------------------------------------------------------------------------------------------------------------------------
WEEK_5|123|Y|1|123|Y|100|300
WEEK_1|123|Y|1|123|Y|0|100
WEEK_1|678|N|2|564|Y|0|900
WEEK_5|345|N|2|859|N|0|658
WEEK_9|789|N|3|458|Y|0|200

I found that following a procedural approach like below will give me the desired output. 我发现遵循下面的程序方法会给我想要的输出。 But I was thinking if this could be done using a single query. 但我在想是否可以使用单个查询来完成。 Need your valuable suggestions on this. 需要你提出宝贵的建议。

    BEGIN
       for i in (select distinct a.report_date curr_date, b.report_date prev_date from TableA a, TableA b where a.report_date-28=b.report_date  order by a.report_date)

        LOOP

         insert into TARGET_TABLE  
          select nvl (curr.WEEK, prev.WEEK) WEEK,
               nvl (curr.COL1, prev.COL1) COL1,
               nvl (curr.COL2, prev.COL2) COL2,
               nvl (curr.COL3, prev.COL3) COL3,   
               nvl (curr.COL4, prev.COL4) COL4,
               nvl (curr.COL5, prev.COL5) COL5,
               nvl (prev.CLOSING_BALANCE, 0) CLOSING_BALANCE_28DAYS_AGO,
               nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
          from TableA curr
               inner join TableA prev
                 on curr.report_date-28= prev.report_date
                  and curr.COL1 = prev.COL1
                     and curr.COL3 = prev.COL3
                     and curr.COL4 = prev.COL4
                     and curr.COL2 = prev.COL2
                     and curr.COL5 = prev.COL5
                     where curr.report_date = i.curr_date
                  and  prev.report_date = i.prev_date;

        commit;             

         insert into TARGET_TABLE  
        select nvl (curr.WEEK, prev.WEEK) WEEK,
               nvl (curr.COL1, prev.COL1) COL1,
               nvl (curr.COL2, prev.COL2) COL2,
               nvl (curr.COL3, prev.COL3) COL3,   
               nvl (curr.COL4, prev.COL4) COL4,
               nvl (curr.COL5, prev.COL5) COL5,
               nvl (prev.CLOSING_BALANCE, 0) CLOSING_BALANCE_28DAYS_AGO,
               nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
          from TableA curr
               left outer join TableA prev
                  on curr.report_date-28= prev.report_date
                  and curr.COL1 = prev.COL1
                     and curr.COL3 = prev.COL3
                     and curr.COL4 = prev.COL4
                     and curr.COL2 = prev.COL2
                     and curr.COL5 = prev.COL5             
               where curr.report_date = i.curr_date  
                  and not exists (select 1 from TARGET_TABLE tmp
                            where tmp.COL1 = curr.COL1
                     and tmp.COL3 = curr.COL3
                     and tmp.COL4 = curr.COL4
                     and tmp.COL2 = curr.COL2
                     and tmp.COL5 = curr.COL5)   ;
        commit;


        insert into TARGET_TABLE  
        select nvl (curr.WEEK, prev.WEEK) WEEK,
               nvl (curr.COL1, prev.COL1) COL1,
               nvl (curr.COL2, prev.COL2) COL2,
               nvl (curr.COL3, prev.COL3) COL3,   
               nvl (curr.COL4, prev.COL4) COL4,
               nvl (curr.COL5, prev.COL5) COL5,
               nvl (prev.CLOSING_BALANCE, 0) CLOSING_BALANCE_28DAYS_AGO,
               nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
          from TableA curr
               right outer join TableA prev
                  on curr.report_date-28= prev.report_date
                  and curr.COL1 = prev.COL1
                     and curr.COL3 = prev.COL3
                     and curr.COL4 = prev.COL4
                     and curr.COL2 = prev.COL2
                     and curr.COL5 = prev.COL5             
               where prev.report_date = i.prev_date  
                  and not exists (select 1 from TARGET_TABLE tmp
                            where tmp.COL1 = prev.COL1
                     and tmp.COL3 = prev.COL3
                     and tmp.COL4 = prev.COL4
                     and tmp.COL2 = prev.COL2
                     and tmp.COL5 = prev.COL5)   ;
        commit;

    end loop;
    end;
    /

OK then, this gives the desired result on given data: 好的,这给出了给定数据的预期结果:

SELECT nvl (curr.week, prev.week) year_week,
    nvl (curr.COL1, prev.COL1) COL1,
    nvl (curr.COL2, prev.COL2) COL2,
    nvl (curr.COL3, prev.COL3) COL3,   
    nvl (curr.COL4, prev.COL4) COL4,
    nvl (curr.COL5, prev.COL5) COL5,
    nvl (prev.CLOSING_BALANCE, 0) PREV_CLOSING_BALANCE_28DAYS_AGO,
    nvl (curr.CLOSING_BALANCE, 0) CURR_CLOSING_BALANCE
FROM TableA curr
FULL OUTER JOIN TableA prev
    ON curr.REPORT_DATE - 28 = prev.report_date
    AND curr.COL1 = prev.COL1
    AND curr.COL3 = prev.COL3
    AND curr.COL4 = prev.COL4
    AND curr.COL2 = prev.COL2
    AND curr.COL5 = prev.COL5
JOIN (
    SELECT DISTINCT a.week prev_week, b.week curr_week, a.report_date prev_date, b.report_date curr_date 
    FROM TableA a
    JOIN TableA b ON a.report_date+28=b.report_date
    ORDER BY a.report_date
) AS dates
    ON (curr.week = dates.curr_week AND curr.REPORT_DATE = dates.curr_date)
        OR (prev.week = dates.prev_week AND prev.REPORT_DATE = dates.prev_date AND curr.REPORT_DATE IS NULL)
WHERE curr.report_date IS NOT NULL OR NOT EXISTS (
    SELECT a.week 
    FROM TableA a 
    JOIN TableA b ON a.report_date+28=b.report_date 
    WHERE b.week = prev.week AND b.report_date = prev.report_date
)
ORDER BY curr.col1;

But the code is pretty complex, so please run some tests on a larger dataset. 但是代码非常复杂,所以请在更大的数据集上运行一些测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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