it-swarm.com.ru

Несколько агрегатных функций в одном запросе SQL из одной таблицы с использованием разных условий

Я работаю над созданием SQL-запроса, который будет извлекать записи из таблицы на основе значения двух агрегатных функций. Эти агрегатные функции извлекают данные из одной и той же таблицы, но с разными условиями фильтрации. Проблема, с которой я сталкиваюсь, заключается в том, что результаты SUM намного больше, чем если бы я включил только одну функцию SUM. Я знаю, что могу создать этот запрос, используя временные таблицы, но мне просто интересно, есть ли элегантное решение, которое требует только одного запроса.

Я создал упрощенную версию, чтобы продемонстрировать проблему. Вот структуры таблиц:

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

И вот запрос:

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

Любое понимание будет с благодарностью.

10
Eric Ness
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

Правка:

Это не имеет большого значения, но я ненавижу повторять условия, чтобы мы могли рефакторинг, как:

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

Таким образом, если вы измените состояние своего дела, это только в одном месте.

22
Jeremy

Группируйте разные вещи отдельно, объединяйтесь в группы.

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

Кроме того, если только ключевые слова SQL являются заглавными, а остальные нет, читаемость увеличивается. ПО МОЕМУ МНЕНИЮ.

4
Tomalak
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 
0
HLGEM