2012-10-16 11 views
5

Ho la seguente struttura:SQL: somma di un valore ma solo per ID distinti - somma condizionale?

Giorno con più eventi di typ1 e typ2, dove typ1 e typ2 hanno chiavi esterne ai rispettivi giorni. Typ2 ha anche durata.

Ora voglio contare tutti gli eventi typ1, tutti gli eventi typ2 e la somma della durata typ2.

Esempio Dati:

Giorno:

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 

Ora voglio il risultato:

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

Il mio problema è la somma, ho bisogno di qualcosa come "somma per distinto typ2.ID" ... Qualcuno sa un modo per risolverlo?

sto usando qualcosa di simile a quanto segue, ma che ovviamente non funziona nel modo desiderato:

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; 
+0

Che tipo di RDBMS e quale versione? – Tobsey

risposta

13

Il mio approccio generale a questo è quello di pre-aggregati ogni tabella, prima di entrare .

In parte perché in realtà non si sommano valori distinti (se ognuna delle due righe aveva 10, la risposta è ancora 20).

Ma soprattutto perché in realtà è più semplice in questo modo. Le sottoquery eseguono l'aggregazione, quindi i join sono tutti 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 
+1

. . Spero che questa sia la risposta accettata, perché è l'approccio giusto. –

+0

Grazie mille, nella mia domanda reale che è più complessa, che rende davvero molto più leggibile – prom85

0
SELECT day.id, 
    count(DISTINCT typ1.id), 
    count(DISTINCT typ2.id), 
    (select sum(t2.duration) 
    from typ2 t2 
    where t2.id = day.id 
    ) AS duration 
FROM days 
    LEFT JOIN typ 
      ON day.id = typ1.id 
    LEFT JOIN typ2 
      ON day.id = typ2.id 
GROUP BY day.id; 
+0

Questo introduce ulteriori sottoquery e credo che l'OP cercasse una soluzione di query singola. La tua risposta significa implicitamente che non può essere scritta come una singola query? – Yuck

+0

@Yuck - Dove si dice "query singola" o "nessuna sotto-query". Perché consideri le "sottoquery" non parte di una "singola query"? * (Se sono un 'sub-' di qualcosa, sono parte di esso, e 'it' è una singola query ...) * Per non parlare del fatto che alcuni RDBMS sono eccezionali per le sottoclassi che escono. – MatBailie

+0

FWIW che non è il mio downvote. E almeno in SQL Server, questo tipo di query ha (spesso) severe penalità prestazionali. Non che sia sbagliato. Stavo solo facendo la domanda - c'è un modo per farlo senza selezionare i tavoli coinvolti? – Yuck