Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL: sum of a value but for distinct ids only - conditional sum?

I have following structure:

Day with multiple events of typ1 and typ2, where typ1 and typ2 have foreign keys to their respective days. Typ2 also has duration.

Now I want to count all typ1 events, all typ2 events and sum of the typ2 duration.

Example Data:

Day:

ID = 1 | Date = yesterday | ...

Typ1:

ID = 1 | FK_DAY = 1 | ...

ID = 2 | FK_DAY = 1 | ...

Typ2:

ID = 1 | FK_DAY = 1 | duration = 10

ID = 2 | FK_DAY = 1 | duration = 20

I now want the result:

Day.ID = 1 | countTyp1 = 2 | countTyp2 = 2 | sumDurationTyp2 = 30

My problem is the sum, I need something like "sum for distinct typ2.ID"... Does anyone know a way to solve that?

I'm using something like the following, but that of course does not work the way I want:

SELECT day.id,
   count( DISTINCT typ1.id ),
   count( DISTINCT typ2.id ),
   sum( duration ) AS duration
FROM days
   LEFT JOIN typ
          ON day.id = typ1.id
   LEFT JOIN typ2
          ON day.id = typ2.id
GROUP BY day.id;
like image 747
prom85 Avatar asked Oct 16 '12 12:10

prom85


People also ask

Can we use distinct with sum in SQL?

You can use the SQL DISTINCT clause within the SQL SUM function.

How do you sum distinct values in SQL?

Syntax. The syntax of a SUM() function in SQL Server are given below: SELECT SUM( DISTINCT aggregate_expression) FROM table_name(s)

Can we use distinct with count (*)?

Yes, you can use COUNT() and DISTINCT together to display the count of only distinct rows.

Can we use sum function in where clause?

SQL SUM() with where clause We can selectively find the sum of only those rows, which satisfy the given condition. To do this, we can use the where clause in the SQL statement.


1 Answers

My general approach to this is to pre-aggregate each table, before joining.

Partly because you're not actually summing distinct values (if each of the two rows had 10, the answer is still 20).

But mostly because it's actually simpler that way. The sub-queries do the aggregation, then the joins are all 1:1.

SELECT
  days.id,
  typ_agg.rows,
  type2_agg.rows,
  type2_agg.duration
FROM
  days
LEFT JOIN
  (SELECT fk_day, COUNT(*) as rows FROM typ GROUP BY fk_day)  AS typ_agg
    ON days.id = typ_agg.fk_day
LEFT JOIN
  (SELECT fk_day, COUNT(*) as rows, SUM(duration) as duration FROM typ2 GROUP BY fk_day)  AS typ2_agg
    ON days.id = typ2_agg.fk_day
like image 168
MatBailie Avatar answered Nov 14 '22 21:11

MatBailie