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

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

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

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

Любое понимание значительно ценилось бы.

12
задан Eric Ness 16 April 2010 в 16:52
поделиться

3 ответа

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:

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

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

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

24
ответ дан 2 December 2019 в 05:27
поделиться

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

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
ответ дан 2 December 2019 в 05:27
поделиться
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
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: