简体   繁体   English

如何比较表中的行并在Oracle中保留行中的最高值

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

A test on db<>fiddle heredb<>fiddle 的测试在这里

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))

dbfiddle 数据库小提琴

It should be faster than @LukStorms recursive solution, which is good and works too.它应该比@LukStorms 递归解决方案更快,这很好并且也有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 SQL 如何比较同一表中两行的值并找到最大值然后 select 是整行 - In SQL how to compare values in two rows in the same table and find the highest value and then select its the entire row 如何计算表中所有行的静态平均值以将单个行值与Oracle SQL中的值进行比较 - How to calculate a static average value of all rows in a Table to compare individual row values to in Oracle SQL 如何在ORACLE中按顺序选择具有最高值的行 - How to select the rows with highest values in sequence in ORACLE 如何为Oracle比较同一表中的行 - How to compare rows in same table for Oracle Oracle如何比较行? - Oracle How To Compare Rows? Oracle-根据表2中的行值在表1中选择列值作为行 - Oracle - Selecting column values as rows in table 1 based on row value in table 2 如何比较同一表中的列值/行 - How to compare column values/rows in same table SQL:如何比较同一表中的两行,其中第二行由第一个值给出 - SQL: How to compare two rows from same table where second row is given by first's values 如何比较Oracle中一组行的最大和最小日期的列值? - How to compare the column values of the max and min dates of a group of rows in Oracle? Oracle SQL - 如何比较同一个表中两组之间的行数? - Oracle SQL - How to compare the number of rows between 2 sets in the same table?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM