[英]How to compare rows in a table and keep the highest values in the row in Oracle
I am looking for a query which will compare the current row value with previous row value and if the percentage of different between current and previous is less than 10% then keep the previous value.我正在寻找一个查询,它将当前行值与前一行值进行比较,如果当前和前一个之间的差异百分比小于 10%,则保留前一个值。 I am sure this can be achievable using oracle lag functions but I am unable to find the exact solution.
我确信使用 oracle 滞后函数可以实现这一点,但我无法找到确切的解决方案。 I have tried below query but it is not keeping the previous value for future rows.
我试过下面的查询,但它没有保留未来行的先前值。 Any help on this would be greatly appreciated.
对此的任何帮助将不胜感激。
I have used the below query to fetch the results but it didn't solve my problem.我使用下面的查询来获取结果,但它没有解决我的问题。
select /*+ parallel(64) */ a, b, c, datevalue, pricevalue,
lag(pricevalue,1,0) over (partition by a, b, c order by a, b, c, datevalue) as prev_pricevalue,
(pricevalue - lag(pricevalue,1,0) over (partition by a, b, c order by a, b, c, datevalue))/pricevalue as diff,
case
when (pricevalue - lag(pricevalue,1,0) over (partition by a, b, c order by a, b, c, datevalue))/pricevalue
< 0.1 then lag(pricevalue,1,0) over (partition by a, b, c order by a, b, c, datevalue)
else pricevalue
end new_pricevalue
from table1
where datevalue between '18-MAY-2019' and '31-MAY-2019';
I have data like below.我有如下数据。 Column names are, A,B,C,DATE and VALUE
列名称为 A、B、C、DATE 和 VALUE
A B C DATE VALUE
16587EA_1005 RETAIL 7207 18/05/2019 7.04
16587EA_1005 RETAIL 7207 19/05/2019 7.04
16587EA_1005 RETAIL 7207 20/05/2019 7.04
16587EA_1005 RETAIL 7207 21/05/2019 7.04
16587EA_1005 RETAIL 7207 22/05/2019 7.04
16587EA_1005 RETAIL 7207 23/05/2019 7
16587EA_1005 RETAIL 7207 24/05/2019 7
16587EA_1005 RETAIL 7207 25/05/2019 7
16587EA_1005 RETAIL 7207 26/05/2019 7
16587EA_1005 RETAIL 7207 27/05/2019 7
16587EA_1005 RETAIL 7207 28/05/2019 7
16587EA_1005 RETAIL 7207 29/05/2019 8
16587EA_1005 RETAIL 7207 30/05/2019 8
16587EA_1005 RETAIL 7207 31/05/2019 8
16587EA_1005 RETAIL 7207 01/06/2019 8.05
16587EA_1005 RETAIL 7207 02/06/2019 8.05
16587EA_1005 RETAIL 7207 03/06/2019 8.05
And, I want the output like below.而且,我想要如下输出。
A B C DATE VALUE
16587EA_1005 RETAIL 7207 18/05/2019 7.04
16587EA_1005 RETAIL 7207 19/05/2019 7.04
16587EA_1005 RETAIL 7207 20/05/2019 7.04
16587EA_1005 RETAIL 7207 21/05/2019 7.04
16587EA_1005 RETAIL 7207 22/05/2019 7.04
16587EA_1005 RETAIL 7207 23/05/2019 7.04
16587EA_1005 RETAIL 7207 24/05/2019 7.04
16587EA_1005 RETAIL 7207 25/05/2019 7.04
16587EA_1005 RETAIL 7207 26/05/2019 7.04
16587EA_1005 RETAIL 7207 27/05/2019 7.04
16587EA_1005 RETAIL 7207 28/05/2019 7.04
16587EA_1005 RETAIL 7207 29/05/2019 8
16587EA_1005 RETAIL 7207 30/05/2019 8
16587EA_1005 RETAIL 7207 31/05/2019 8
16587EA_1005 RETAIL 7207 01/06/2019 8
16587EA_1005 RETAIL 7207 02/06/2019 8
16587EA_1005 RETAIL 7207 03/06/2019 8
Best Regards MMR最好的问候 MMR
Not exactly a concise method, but a recursive CTE can do this.不完全是一种简洁的方法,但递归 CTE 可以做到这一点。
WITH CTE AS
(
-- adding a rank and rownum
SELECT t.*
, DENSE_RANK() OVER (ORDER BY a, b, c) AS rnk
, ROW_NUMBER() OVER (PARTITION BY a, b, c ORDER BY datevalue) rn
FROM table1 t
),
RCTE (rnk, rn, a, b, c, datevalue, pricevalue) AS
(
-- seeding the recursion
SELECT rnk, rn, a, b, c, datevalue, pricevalue
FROM CTE
WHERE rn = 1
UNION ALL
-- loop through the records for each rank
SELECT c.rnk, c.rn, c.a, c.b, c.c, c.datevalue,
CASE
WHEN ABS(r.pricevalue - c.pricevalue) / c.pricevalue < 0.1
THEN r.pricevalue
ELSE c.pricevalue
END
FROM RCTE r
JOIN CTE c
ON c.rnk = r.rnk
AND c.rn = r.rn + 1
)
SELECT *
FROM RCTE
ORDER BY rnk, rn;
Returns:返回:
\nRNK |RNK | RN |
注册护士 | A |
一个 | B |
乙 | C |
C | DATEVALUE |
日期值 | PRICEVALUE
价格值\n--: |
--: | -: |
-: | :- |
:- | :- |
:- | :- |
:- | :-------- |
:-------- | ---------:
---------:\n 1 |
1 | 1 |
1 | a |
| b |
乙 | c |
| | 18-MAY-19 |
2019 年 5 月 18 日 | 7.04
7.04\n 1 |
1 | 2 |
2 | a |
| b |
乙 | c |
| | 19-MAY-19 |
2019 年 5 月 19 日 | 7.04
7.04\n 1 |
1 | 3 |
3 | a |
| b |
乙 | c |
| | 20-MAY-19 |
19 年 5 月 20 日 | 7.04
7.04\n 1 |
1 | 4 |
4 | a |
| b |
乙 | c |
| | 21-MAY-19 |
2019 年 5 月 21 日 | 7.04
7.04\n 1 |
1 | 5 |
5 | a |
| b |
乙 | c |
| | 22-MAY-19 |
19 年 5 月 22 日 | 7.04
7.04\n 1 |
1 | 6 |
6 | a |
| b |
乙 | c |
| | 23-MAY-19 |
19 年 5 月 23 日 | 7.04
7.04\n 1 |
1 | 7 |
7 | a |
| b |
乙 | c |
| | 24-MAY-19 |
19 年 5 月 24 日 | 7.04
7.04\n 1 |
1 | 8 |
8 | a |
| b |
乙 | c |
| | 25-MAY-19 |
19 年 5 月 25 日 | 7.04
7.04\n 1 |
1 | 9 |
9 | a |
| b |
乙 | c |
| | 26-MAY-19 |
19 年 5 月 26 日 | 7.04
7.04\n 1 |
1 | 10 |
10 | a |
| b |
乙 | c |
| | 27-MAY-19 |
19 年 5 月 27 日 | 7.04
7.04\n 1 |
1 | 11 |
11 | a |
| b |
乙 | c |
| | 28-MAY-19 |
19 年 5 月 28 日 | 7.04
7.04\n 1 |
1 | 12 |
12 | a |
| b |
乙 | c |
| | 29-MAY-19 |
19 年 5 月 29 日 | 8
8\n 1 |
1 | 13 |
13 | a |
| b |
乙 | c |
| | 30-MAY-19 |
19 年 5 月 30 日 | 8
8\n 1 |
1 | 14 |
14 | a |
| b |
乙 | c |
| | 31-MAY-19 |
2019 年 5 月 31 日 | 8
8\n 1 |
1 | 15 |
15 | a |
| b |
乙 | c |
| | 01-JUN-19 |
01-JUN-19 | 8
8\n 1 |
1 | 16 |
16 | a |
| b |
乙 | c |
| | 02-JUN-19 |
02-JUN-19 | 8
8\n
My attempt :) You can detect if change is greater than 10% and use new value there, in other cases leave null.我的尝试 :) 您可以检测变化是否大于 10% 并在那里使用新值,在其他情况下留空。 Then use
lag
with ignore nulls
clause:然后使用带有
ignore nulls
子句的lag
:
select a, b, c, dv, pv,
nvl(cpv, lag(cpv, 1, cpv) ignore nulls over (partition by a, b, c order by dv)) new_pv
from (
select a, b, c, dv, pv, ppv, case when rn = 1 or abs((ppv - pv)/pv) > .01 then pv end cpv
from (
select a, b, c, datevalue dv, pricevalue pv,
row_number() over (partition by a, b, c order by datevalue) rn,
lag(pricevalue) over (partition by a, b, c order by datevalue) ppv
from table1))
It should be faster than @LukStorms recursive solution, which is good and works too.它应该比@LukStorms 递归解决方案更快,这很好并且也有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.