Reputation: 5
Given Number: 2111.03
T1 data:
Name | No |
---|---|
AAA | 2111.03 |
BBB | 1226.79 |
CCC | 965 |
T2 data:
Name | Start Range | End Range |
---|---|---|
AAA | 0 | 100 |
AAA | 100 | 130 |
AAA | 130 | 155 |
AAA | 155 | 99999 |
BBB | 0 | 100 |
BBB | 100 | 120 |
BBB | 120 | 120 |
CCC | 0 | 100 |
CCC | 100 | 110 |
CCC | 110 | 150 |
CCC | 150 | 200 |
Expected Output: Number should go though each range and subtract by the max range, need to show the remaining number at the end.
Name | No |
---|---|
AAA | 100 |
AAA | 30 |
AAA | 55 |
AAA | 1926.03 |
BBB | 100 |
BBB | 20 |
BBB | 0 |
BBB | 1106.79 |
CCC | 100 |
CCC | 10 |
CCC | 40 |
CCC | 50 |
CCC | 765 |
Please help me to write a query in SQL, PLSQL.
There are different names and ranges, but I want to write a query to satisfy all the ranges. Please help me write the query in SQL or PL/SQL
Upvotes: 0
Views: 63
Reputation: 7786
There are some issues regarding your expected result. The logic is not consistent for all names. Max range for name AAA is either 155 or 99999 but you put it in the result like it was 185... There is no additional row for AAA (I put it the same but it could be added if needed)
Anyway, if I got it right maybe this could help, if not then it could guide you to the solution.
Using analytic functions and case expressions you can get all the rows you need with final calculations in the last row for every name. Part of the solution is placed in joined subquery and the rest is in outer sql. Additional rows were added with Union All.
WITH -- S a m p l e D a t a :
t1 AS
( Select 'AAA' "A_NAME", 2111.03 "A_NUMBER" From Dual Union All
Select 'BBB' "A_NAME", 1226.79 "A_NUMBER" From Dual Union All
Select 'CCC' "A_NAME", 965 "A_NUMBER" From Dual
),
t2 AS
( Select 'AAA' "A_NAME", 0 "START_RANGE", 100 "END_RANGE" From Dual Union All
Select 'AAA' "A_NAME", 100 "START_RANGE", 130 "END_RANGE" From Dual Union All
Select 'AAA' "A_NAME", 130 "START_RANGE", 155 "END_RANGE" From Dual Union All
Select 'AAA' "A_NAME", 155 "START_RANGE", 99999 "END_RANGE" From Dual Union All
--
Select 'BBB' "A_NAME", 0 "START_RANGE", 100 "END_RANGE" From Dual Union All
Select 'BBB' "A_NAME", 100 "START_RANGE", 120 "END_RANGE" From Dual Union All
Select 'BBB' "A_NAME", 120 "START_RANGE", 120 "END_RANGE" From Dual Union All
--
Select 'CCC' "A_NAME", 0 "START_RANGE", 100 "END_RANGE" From Dual Union All
Select 'CCC' "A_NAME", 100 "START_RANGE", 110 "END_RANGE" From Dual Union All
Select 'CCC' "A_NAME", 110 "START_RANGE", 150 "END_RANGE" From Dual Union All
Select 'CCC' "A_NAME", 150 "START_RANGE", 200 "END_RANGE" From Dual
)
-- M a i n S Q L :
SELECT A_NAME, A_NUMBER
FROM ( SELECT t1.A_NAME,
Case When t2.END_RANGE != 99999 Then t2.DIFF Else t1.A_NUMBER - Max(t2.START_RANGE) Over(Partition By t1.A_NAME) End "A_NUMBER",
t2.RN
FROM t1
INNER JOIN ( Select ROW_NUMBER() OVER(Partition By A_NAME Order By START_RANGE) "RN",
A_NAME,
START_RANGE,
END_RANGE,
Max(Case When END_RANGE < 99999 Then END_RANGE End)
Over(Partition By A_NAME Order By START_RANGE
Rows Between Unbounded Preceding And Current Row) - START_RANGE "DIFF"
From t2
Order By t2.A_NAME, t2.START_RANGE
) t2 ON(t2.A_NAME = t1.A_NAME)
Union All
SELECT t1.A_NAME, t1.A_NUMBER - Max(t2.END_RANGE) "A_NUMBER", 999 "RN"
FROM t1
INNER JOIN t2 ON(t2.A_NAME = t1.A_NAME)
GROUP BY t1.A_NAME, t1.A_NUMBER
HAVING Max(t2.END_RANGE) < 99999
)
ORDER BY A_NAME, RN
/* R e s u l t :
A_NAME A_NUMBER
------ ----------
AAA 100
AAA 30
AAA 25
AAA 1956,03
BBB 100
BBB 20
BBB 0
BBB 1106,79
CCC 100
CCC 10
CCC 40
CCC 50
CCC 765 */
Upvotes: 0