简体   繁体   中英

Oracle SQL: Select a Max and Min Value from a Group

From multiple tables I'm currently selecting a product, value, and contract period. I want to group the results by product and shipment period while summing the value.

My contract period can either be arrival based or shipment based. So, currently to determine which contract period to use, I'm looking to see if one of the period descriptions is null then populating the period end and begin dates as either ship or arrival based on that. Specifically, I'm using the following.

DECODE((P.SHIP_PERIOD_DESCR), NULL, 
'ARRIVE'  || ' '  ||P.ARRIVAL_PERIOD_BEGIN || ' - '  || P.ARRIVAL_PERIOD_END, 
'SHIP'  || ' '  ||P.SHIP_PERIOD_BEGIN || ' - '  || P.SHIP_PERIOD_END)

My results are as such:

PRODUCT     VALUE      CONTRACT_PERIOD
APPLES      $600        SHIP 01-FEB-16 - 15-MAR-16
APPLES      $700        SHIP 01-MAR-16 - 15-APR-16
LEMONS      $200        SHIP 15-JAN-16 - 31-JAN-16
LEMONS      $150        SHIP 01-FEB-16 - 15-FEB-16
LEMONS      $200        ARRIVE 15-FEB-16 - 28-FEB-16
LEMONS      $250        ARRIVE 01-MAR-16 - 15-MAR-16

What I would like to see is the min ship or arrival date and max ship or arrival date per product as such:

PRODUCT     VALUE      CONTRACT_PERIOD
APPLES      $1,300      SHIP 01-FEB-16 - 15-APR-16
LEMONS      $350        SHIP 15-JAN-16 - 15-FEB-16
LEMONS      $450        ARRIVE 15-FEB-16 - 15-MAR-16

Any suggestions on a way to determine which contract is valid, then group the results using the min and max dates while not interchanging a ship date for an arrival date would be greatly appreciated.

The basic idea is not to combine the different columns into a single concatenated column. Then use intelligent aggregation:

with t as (
      <basically your query here, but with each column individually>
     )
select product, ship_period_desc,
       min(case when ship_period_desc = 'ARRIVAL' then ARRIVAL_PERIOD_BEGIN
                else SHIP_PERIOD_BEGIN
           end) as PERIOD_BEGIN,
       min(case when ship_period_desc = 'ARRIVAL' then ARRIVAL_PERIOD_END
                else SHIP_PERIOD_END
           end) as PERIOD_END
from t
where ship_period_desc in ('ARRIVAL', 'SHIP')
group by product, ship_period_desc;

Oracle Setup :

CREATE TABLE table_name ( product, value, ship_period_descr, arrival_period_begin, arrival_period_end, ship_period_begin, ship_period_end ) AS
SELECT 'Apples', 600, 'X', NULL, NULL, DATE '2016-02-01', DATE '2016-03-15' FROM DUAL UNION ALL
SELECT 'Apples', 700, 'X', NULL, NULL, DATE '2016-03-01', DATE '2016-04-16' FROM DUAL UNION ALL
SELECT 'Lemons', 200, 'X', NULL, NULL, DATE '2016-01-15', DATE '2016-01-31' FROM DUAL UNION ALL
SELECT 'Lemons', 150, 'X', NULL, NULL, DATE '2016-02-01', DATE '2016-02-15' FROM DUAL UNION ALL
SELECT 'Lemons', 200, NULL, DATE '2016-02-15', DATE '2016-02-28', NULL, NULL FROM DUAL UNION ALL
SELECT 'Lemons', 250, NULL, DATE '2016-03-01', DATE '2016-03-15', NULL, NULL FROM DUAL;

Query :

SELECT   Product,
         SUM( Value ) AS Value,
         DECODE(
           DECODE( P.SHIP_PERIOD_DESCR, NULL, 1, 0 ),
           1, 'ARRIVE ' || MIN( P.ARRIVAL_PERIOD_BEGIN ) || ' - ' || MAX( P.ARRIVAL_PERIOD_END ),
              'SHIP ' || MIN( P.SHIP_PERIOD_BEGIN ) || ' - ' || MAX( P.SHIP_PERIOD_END )
         ) AS Contract_Period
FROM     table_name p
GROUP BY Product,
         DECODE( P.SHIP_PERIOD_DESCR, NULL, 1, 0 );

Results :

PRODUCT      VALUE CONTRACT_PERIOD                              
------- ---------- ----------------------------------------------
Apples        1300 SHIP 01-FEB-16 - 16-APR-16                     
Lemons         350 SHIP 15-JAN-16 - 15-FEB-16                     
Lemons         450 ARRIVE 15-FEB-16 - 15-MAR-16                   

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