简体   繁体   中英

Oracle SQL: How to select the MAX value from a derived column

I have a table (STUFF) with 3 columns (item, old_value, new_value). I would like to retrieve all the items with the highest percentage change in value. The following query produces a "group function is not allowed here" error. How do I go about fixing this?

SELECT    item, 
          old_value, 
          new_value, 
          highest_percentage
FROM      (SELECT item, old_value, new_value, 
                  (new_value - old_value) / old_value * 100 AS highest_percentage
          FROM    STUFF)
WHERE     highest_percentage = MAX(highest_percentage);

This is the table

CREATE TABLE STUFF
( item      VARCHAR2(30) PRIMARY KEY,
  old_value     NUMBER(6, 2),
  new_value     NUMBER(6, 2));

INSERT INTO STUFF VALUES('E1',  0.62,  1.78);
INSERT INTO STUFF VALUES('B1',  0.80,  3.28);
INSERT INTO STUFF VALUES('B2',  2.72,  7.36);
INSERT INTO STUFF VALUES('M4',  2.70,  5.65);
INSERT INTO STUFF VALUES('T6',  5.70,  6.65);
INSERT INTO STUFF VALUES('R3',  4.00, 16.40);
INSERT INTO STUFF VALUES('G10',  8.00, 32.80);

Ideally I should have this output.

ITEM                OLD_VALUE NEW_VALUE HIGHEST_PERCENTAGE       
------------------- --------- --------- ------------------
B1                  0.80      3.28      310                                    
G10                 8.00      32.80     310                                   
R3                  4.00      16.40     310

It's called a Top-N query in Oracle you can do it like:

select * from 
    (select * from XXX order by YYY desc) 
  where rownum < N;

According to your latest update - a scalar sub-query helps in this case:

SELECT * FROM STUFF 
  WHERE (new_value - old_value) / old_value * 100 = 
    (SELECT max((new_value - old_value) / old_value * 100) AS highest_percentage  
        FROM STUFF)

To avoid extra sub-querying:

SELECT * FROM 
  STUFF,
  (SELECT max((new_value - old_value) / old_value * 100) AS percentage FROM STUFF) highest
WHERE (new_value - old_value) / old_value * 100 = highest.percentage ;

However Analytic function seems to be the fastest solution.

Another option is to use a window function that calculates the max percentage while retrieving the data. This is probably faster than the solution with a sub-query as the table only needs to be accessed once:

with data as (
  SELECT item, 
         old_value, 
         new_value, 
         (new_value - old_value) / old_value * 100 AS highest_percentage,
         max((new_value - old_value) / old_value * 100) over () as max_pct
  FROM STUFF
)
SELECT item, 
       old_value, 
       new_value, 
       highest_percentage
FROM data   
WHERE highest_percentage = max_pct;

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM