[英]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.