Reputation: 1
My oracle table data is as below.
Org_ID | Product_ID | Order_Month | Amount |
---|---|---|---|
101 | 201 | JAN-2021 | 2000 |
101 | 201 | FEB-2021 | 2000 |
101 | 201 | MAR-2021 | 2000 |
101 | 201 | APR-2021 | 1500 |
101 | 201 | MAY-2021 | 2000 |
101 | 202 | JUN-2021 | 2000 |
101 | 202 | JUL-2021 | 2000 |
We need to compare previous value for amount and find records with mis-matched amount and with respect to Product_ID
.
My output should be like below. Tried using lag but couldn't find the solution. Can someone please provides inputs on how to approach for solving this.
Org_ID | Product_ID | Order_Month | Amount |
---|---|---|---|
101 | 201 | JAN-2021 to MAR-2021 | 2000 |
101 | 201 | APR-2021 to APR-2021 | 1500 |
101 | 201 | MAY-2021 to MAY-2021 | 1500 |
101 | 202 | JUN-2021 to JUL-2021 | 1500 |
Upvotes: 0
Views: 358
Reputation: 1270993
This is a type of gaps-and-islands problem. In this case, the simplest solution is probably the difference of row numbers. The following assumes that order_month
is actually a string (rather than a date):
select org_id, product_id, amount,
min(order_month), max(order_month)
from (select t.*,
row_number() over (partition by org_id, product_id order by to_date(order_month, 'MON-YYYY')) as seqnum,
row_number() over (partition by org_id, product_id, amount order by to_date(order_month, 'MON-YYYY')) as seqnum_2
from t
) t
group by org_id, product_id, amount, (seqnum - seqnm_2);
Why this works is a little tricky to explain. However, if you look at the results of the subquery, you will see how the difference between these two values is constant on adjacent months.
Upvotes: 0
Reputation: 10035
You may try the following
SELECT
"Org_ID",
"Product_ID",
CONCAT(
CONCAT(Order_Month_Group,' to '),
TO_CHAR(MAX(actual_date),'MON-YYYY')
) as Order_Month,
"Amount"
FROM (
SELECT
t1.*,
LAG(
"Order_Month",
CASE WHEN continued=0 THEN 0 ELSE seq_num-1 END
,"Order_Month") OVER (
PARTITION BY "Org_ID","Product_ID","Amount"
ORDER BY actual_date
) as Order_Month_Group
FROM (
SELECT
t.*,
TO_DATE(t."Order_Month",'MON-YYYY') as actual_date,
ROW_NUMBER() OVER (
PARTITION BY t."Org_ID",t."Product_ID",t."Amount"
ORDER BY TO_DATE("Order_Month",'MON-YYYY')
) as seq_num,
CASE
WHEN t."Amount" = LAG(t."Amount",1,t."Amount") OVER (
PARTITION BY t."Org_ID",t."Product_ID"
ORDER BY TO_DATE("Order_Month",'MON-YYYY')
) THEN 1
ELSE 0
END as continued
FROM
my_oracle_table t
) t1
) t2
GROUP BY "Org_ID", "Product_ID", Order_Month_Group, "Amount"
ORDER BY MIN(actual_date)
or
SELECT
"Org_ID",
"Product_ID",
CONCAT(
CONCAT(TO_CHAR(MIN(actual_date),'MON-YYYY'),' to '),
TO_CHAR(MAX(actual_date),'MON-YYYY')
) as Order_Month,
"Amount"
FROM (
SELECT
t1.*,
SUM(continued) OVER ( ORDER BY actual_date) as grp
FROM (
SELECT
t.*,
TO_DATE("Order_Month",'MON-YYYY') as actual_date,
CASE
WHEN t."Amount" = LAG(t."Amount",1,t."Amount") OVER (
PARTITION BY t."Org_ID",t."Product_ID"
ORDER BY TO_DATE("Order_Month",'MON-YYYY')
) THEN 0
ELSE 1
END as continued
FROM
my_oracle_table t
) t1
) t2
GROUP BY "Org_ID", "Product_ID", grp, "Amount"
ORDER BY MIN(actual_date)
Let me know if this works for you.
Upvotes: 1