Im looking to sum a column until a defined value then ignore the rest of the records.
ID | WHEN | VALUE | AVG_COL |
---|---|---|---|
101 | 2016 | 6 | 84.5 |
101 | 2015 | 3 | 76 |
101 | 2014 | 3 | 87 |
101 | 2013 | 15 | 85.8 |
101 | 2012 | 6 | 92 |
101 | 2011 | 3 | 81 |
101 | 2010 | 3 | 82.3 |
I need a single result set of
ID | VALUE | AVG_COL |
---|---|---|
101 | 30 | 82.3 |
I have tried the following
SELECT
ID,
WHEN,
VALUE,
AVG_COL,
SUM(VALUE) OVER (PARTITION BY ID ORDER BY WHEN) AS VALUE, --must equal 30
AVG(AVG_COL) OVER (PARTITION BY ID) AVG
FROM
TABLE_ONE
WHERE
VALUE = 30;
Any help would be greatly appreciated!
Hi try some thing like this, where modified the WHERE clause
-- Untested
SELECT
ID,
WHEN,
VALUE,
AVG_COL,
SUM(VALUE) OVER (PARTITION BY ID ORDER BY WHEN) AS VALUE, --must equal 30
AVG(AVG_COL) OVER (PARTITION BY ID) AVG
FROM
TABLE_ONE
WHERE
ID IN (SELECT ID FROM ( (SELECT ID, sum(VALUE) sum_val FROM
TABLE_ONE GROUP BY ID) WHERE SUM_VAL = 30);
try this
select id,
SUM(VALUE) OVER (PARTITION BY ID ORDER BY WHEN RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS VALUE,
AVG(AVG_COL) OVER (PARTITION BY ID) AVG
from table_one
where VALUE <= 30
order by when desc
fetch first 1 rows only;
You can compute the running sum with window functions, then filter and limit in an outer query.
Assuming a table like (id, dt, val, . . .)
:
select *
from (
select t.*,
sum(val) over(partition by id order by dt) sum_val
from mytable t
) t
where sum_val >= 30
order by row_number() over(partition by id order by dt desc)
fetch first row with ties
Notes:
What you need is running sum of values and a decision on what order by you want to apply for that running sum.
SAMPLE DATA
WITH
tbl AS
(
Select 101 "ID", 2016 "YR", 6 "VAL", 84.5 "AVG_COL" From Dual Union All
Select 101 "ID", 2015 "YR", 3 "VAL", 76 "AVG_COL" From Dual Union All
Select 101 "ID", 2014 "YR", 3 "VAL", 87 "AVG_COL" From Dual Union All
Select 101 "ID", 2013 "YR", 15 "VAL", 85.8 "AVG_COL" From Dual Union All
Select 101 "ID", 2012 "YR", 6 "VAL", 92 "AVG_COL" From Dual Union All
Select 101 "ID", 2011 "YR", 3 "VAL", 81 "AVG_COL" From Dual Union All
Select 101 "ID", 2010 "YR", 3 "VAL", 82.3 "AVG_COL" From Dual
),
Create CTE (I named it grid) to prepare your data - in this case I used descending order by years:
grid AS
(
Select
ID, YR,
VAL,
Sum(VAL) OVER(Partition By ID Order By YR DESC Rows Between Unbounded Preceding And Current Row) "RUNNING_SUM",
CASE WHEN Sum(VAL) OVER(Partition By ID Order By YR DESC Rows Between Unbounded Preceding And Current Row) >= 30
THEN Sum(1) OVER(Partition By ID Order By YR DESC Rows Between Unbounded Preceding And Current Row)
END "IS_OVER_RN",
AVG_COL,
Round(AVG(AVG_COL) OVER(Partition By ID Order By YR DESC Rows Between Unbounded Preceding And Current Row), 2) "RUNNING_AVG"
From
tbl
)
This cte is resulting as:
ID YR VAL RUNNING_SUM IS_OVER_RN AVG_COL RUNNING_AVG
---------- ---------- ---------- ----------- ---------- ---------- -----------
101 2016 6 6 84.5 84.5
101 2015 3 9 76 80.25
101 2014 3 12 87 82.5
101 2013 15 27 85.8 83.33
101 2012 6 33 5 92 85.06
101 2011 3 36 6 81 84.38
101 2010 3 39 7 82.3 84.09
Now you can get your result with the code below
-- Main SQL
SELECT
ID, RUNNING_SUM, RUNNING_AVG
FROM
grid g
WHERE IS_OVER_RN = (Select Min(IS_OVER_RN) From grid Where ID = g.ID)
Result:
-- with YEARS in DESCENDING order
ID RUNNING_SUM RUNNING_AVG
---------- ----------- -----------
101 33 85.06
If you make orderings within analytic functions in grid cte ASCENDING then the same main SQL would result with:
-- with YEARS in ASCENDING order
ID RUNNING_SUM RUNNING_AVG
---------- ----------- -----------
101 30 82.5
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.