sk1007
sk1007

Reputation: 581

How to use distinct and sum both together in oracle?

For example my table contains the following data:

ID    price    
-------------
 1     10      
 1     10 
 1     20     
 2     20      
 2     20      
 3     30
 3     30
 4     5
 4     5
 4     15

So given the example above,

ID    price    
-------------
 1     30          
 2     20           
 3     30
 4     20
-----------
ID     100

How to write query in oracle? first sum(distinct price) group by id then sum(all price).

Upvotes: 1

Views: 22407

Answers (5)

MT0
MT0

Reputation: 168406

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE TABLE MYTABLE ( ID, price ) AS
          SELECT 1, 10 FROM DUAL
UNION ALL SELECT 1, 10 FROM DUAL
UNION ALL SELECT 1, 20 FROM DUAL
UNION ALL SELECT 2, 20 FROM DUAL
UNION ALL SELECT 2, 20 FROM DUAL
UNION ALL SELECT 3, 30 FROM DUAL
UNION ALL SELECT 3, 30 FROM DUAL
UNION ALL SELECT 4,  5 FROM DUAL
UNION ALL SELECT 4,  5 FROM DUAL
UNION ALL SELECT 4, 15 FROM DUAL;

Query 1:

SELECT COALESCE( TO_CHAR(ID), 'ID' ) AS ID,
       SUM( PRICE ) AS PRICE
FROM   ( SELECT DISTINCT ID, PRICE FROM MYTABLE )
GROUP BY ROLLUP ( ID )
ORDER BY ID

Results:

| ID | PRICE |
|----|-------|
|  1 |    30 |
|  2 |    20 |
|  3 |    30 |
|  4 |    20 |
| ID |   100 |

Upvotes: 0

Raging Bull
Raging Bull

Reputation: 18757

SELECT ID,SUM(price) as price
FROM
(SELECT ID,price
 FROM TableName
 GROUP BY ID,price) as T
 GROUP BY ID

Explanation:

The inner query will select different prices for each ids.

i.e.,

ID    price    
-------------     
 1     10 
 1     20     
 2     20      
 3     30
 4     5
 4     15

Then the outer query will select SUM of those prices for each id.

Final Result :

ID  price
----------
1   30
2   20
3   30
4   20

Result in SQL Fiddle.

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1270703

I would be very careful with a data structure like this. First, check that all ids have exactly one price:

select id
from table t
group by id
having count(distinct price) > 1;

I think the safest method is to extract a particular price for each id (say the maximum) and then do the aggregation:

select sum(price)
from (select id, max(price) as price
      from table t
      group by id
     ) t;

Then, go fix your data so you don't have a repeated additive dimension. There should be a table with one row per id and price (or perhaps with duplicates but controlled by effective and end dates).

The data is messed up; you should not assume that the price is the same on all rows for a given id. You need to check that every time you use the fields, until you fix the data.

Upvotes: 5

dnoeth
dnoeth

Reputation: 60482

First do the DISTINCT and then a ROLLUP

SELECT ID, SUM(price)        -- sum of the distinct prices
FROM
 (
   SELECT DISTINCT ID, price -- distinct prices per ID
   FROM tab
 ) dt
GROUP BY ROLLUP(ID)          -- two levels of aggregation, per ID and total sum

Upvotes: 0

Lalit Kumar B
Lalit Kumar B

Reputation: 49092

first sum(distinct price) group by id then sum(all price)

Looking at your desired output, it seems you also need the final sum(similar to ROLLUP), however, ROLLUP won't directly work in your case.

If you want to format your output in exactly the way you have posted your desired output, i.e. with a header for the last row of total sum, then you could set the PAGESIZE in SQL*Plus.

  • Using UNION ALL

For example,

SQL> set pagesize 7
SQL> WITH DATA AS(
  2  SELECT ID, SUM(DISTINCT price) AS price
  3  FROM t
  4  GROUP BY id
  5  )
  6  SELECT to_char(ID) id, price FROM DATA
  7  UNION ALL
  8  SELECT 'ID' id, sum(price) FROM DATA
  9  ORDER BY ID
 10  /

ID       PRICE
--- ----------
1           30
2           20
3           30
4           20

ID       PRICE
--- ----------
ID         100

SQL>

So, you have an additional row in the end with the total SUM of price.

  • Using ROLLUP

Alternatively, you could use ROLLUP to get the total sum as follows:

SQL> set pagesize 7
SQL> WITH DATA AS
  2    ( SELECT ID, SUM(DISTINCT price) AS price FROM t GROUP BY id
  3    )
  4  SELECT ID, SUM(price) price
  5  FROM DATA
  6  GROUP BY ROLLUP(id);

        ID      PRICE
---------- ----------
         1         30
         2         20
         3         30
         4         20

        ID      PRICE
---------- ----------
                  100

SQL>

Upvotes: 1

Related Questions