2010-04-16 12 views
9

Sto lavorando alla creazione di una query SQL che estrarrà record da una tabella in base al valore di due funzioni di aggregazione. Queste funzioni aggregate estraggono i dati dalla stessa tabella, ma con condizioni di filtro diverse. Il problema che ho riscontrato è che i risultati delle SUM sono molto più grandi di quelli che includo solo una funzione SUM. So che posso creare questa query utilizzando le tabelle temporanee, ma mi chiedo solo se esiste una soluzione elegante che richiede solo una singola query.Più funzioni di aggregazione in una query SQL dalla stessa tabella utilizzando condizioni diverse

Ho creato una versione semplificata per dimostrare il problema. Qui ci sono le strutture delle tabelle:

EMPLOYEE TABLE 

EMPID 
1 
2 
3 

ABSENCE TABLE 

EMPID DATE  HOURS_ABSENT 
1  6/1/2009 3 
1  9/1/2009 1 
2  3/1/2010 2 

Ed ecco la domanda:

SELECT 
    E.EMPID 
    ,SUM(ATOTAL.HOURS_ABSENT) AS ABSENT_TOTAL 
    ,SUM(AYEAR.HOURS_ABSENT) AS ABSENT_YEAR 

FROM 
    EMPLOYEE E 

    INNER JOIN ABSENCE ATOTAL ON 
     ATOTAL.EMPID = E.EMPID 

    INNER JOIN ABSENCE AYEAR ON 
     AYEAR.EMPID = E.EMPID 

WHERE 
    AYEAR.DATE > '1/1/2010' 

GROUP BY 
    E.EMPID 

HAVING 
    SUM(ATOTAL.HOURS_ABSENT) > 10 
    OR SUM(AYEAR.HOURS_ABSENT) > 3 

Tutta la comprensione sarebbe molto apprezzato.

+0

È un po 'di confusione. In base ai dati forniti, qual è il risultato atteso? – Raja

risposta

19
SELECT 
    E.EMPID 
    ,SUM(ABSENCE.HOURS_ABSENT) AS ABSENT_TOTAL 
    ,SUM(case when year(Date) = 2010 then ABSENCE.HOURS_ABSENT else 0 end) AS ABSENT_YEAR 

FROM 
    EMPLOYEE E 

    INNER JOIN ABSENCE ON 
     ABSENCE.EMPID = E.EMPID 

GROUP BY 
    E.EMPID 

HAVING 
    SUM(ATOTAL.HOURS_ABSENT) > 10 
    OR SUM(case when year(Date) = 2010 then ABSENCE.HOURS_ABSENT else 0 end) > 3 

edit:

Non è un grosso problema, ma io odio le condizioni che si ripetono in modo che potessimo refactoring come:

Select * From 
(
    SELECT 
     E.EMPID 
     ,SUM(ABSENCE.HOURS_ABSENT) AS ABSENT_TOTAL 
     ,SUM(case when year(Date) = 2010 then ABSENCE.HOURS_ABSENT else 0 end) AS ABSENT_YEAR 

    FROM 
     EMPLOYEE E 

     INNER JOIN ABSENCE ON 
      ABSENCE.EMPID = E.EMPID 

    GROUP BY 
     E.EMPID 
    ) EmployeeAbsences 
    Where ABSENT_TOTAL > 10 or ABSENT_YEAR > 3 

In questo modo, se si cambia la sua condizione caso, è in uno solo spot.

+0

Grazie mille! Mi hai presentato "caso in cui" ... mi hai fatto uscire dal grande problema che ho avuto! – user979051

0
SELECT E.EMPID , sum(ABSENT_TOTAL) , sum(ABSENT_YEAR) 
FROM 
(SELECT 
    E.EMPID 
    ,SUM(ATOTAL.HOURS_ABSENT) AS ABSENT_TOTAL 
    ,0 AS ABSENT_YEAR 

FROM 
    EMPLOYEE E 

    INNER JOIN ABSENCE ATOTAL ON 
     ATOTAL.EMPID = E.EMPID 
WHERE 
    AYEAR.DATE > '1/1/2010' 

GROUP BY 
    E.EMPID 

HAVING 
    SUM(ATOTAL.HOURS_ABSENT) > 10 

UNION ALL 

SELECT 0  
    ,SUM(AYEAR.HOURS_ABSENT) 
FROM 
    EMPLOYEE E  

     INNER JOIN ABSENCE AYEAR ON 
     AYEAR.EMPID = E.EMPID 

GROUP BY 
    E.EMPID 

HAVING 
    SUM(AYEAR.HOURS_ABSENT) > 3) a 

    GROUP BY A.EMPID 
4

Raggruppare le cose separatamente, unire i gruppi.

SELECT 
    T.EMPID 
    ,T.ABSENT_TOTAL 
    ,Y.ABSENT_YEAR 
FROM 
    (
    SELECT 
     E.EMPID 
     ,SUM(A.HOURS_ABSENT) AS ABSENT_TOTAL 
    FROM 
     EMPLOYEE E 
     INNER JOIN ABSENCE A ON A.EMPID = E.EMPID 
    GROUP BY 
     E.EMPID 
    ) AS T 
    INNER JOIN 
    (
    SELECT 
     E.EMPID 
     ,SUM(A.HOURS_ABSENT) AS ABSENT_YEAR 
    FROM 
     EMPLOYEE E 
     INNER JOIN ABSENCE A ON A.EMPID = E.EMPID 
    WHERE 
     A.DATE > '1/1/2010' 
    GROUP BY 
     E.EMPID 
    ) AS Y 
    ON T.EMPLID = Y.EMPLID 
WHERE 
    ABSENT_TOTAL > 10 OR ABSENT_YEAR > 3 

Inoltre, se solo le parole chiave SQL sono tappi e il resto no, la leggibilità aumenta. A PARER MIO.

Problemi correlati