Создание отчета о времени пользователя, который включает ноль часовых недель - PullRequest
3 голосов
/ 18 мая 2019

Я чертовски потратил время на то, чтобы составить запрос, который, на мой взгляд, был бы довольно простым.У меня есть таблица, которая записывает общее количество часов, потраченных на задачу, и пользователя, который сообщил об этих часах.Мне нужно собрать запрос, который возвращает количество часов, которое данный пользователь взимал за каждую неделю года (включая недели, когда часы не были начислены).

Ожидаемый результат:

    |USER_ID | START_DATE | END_DATE  | HOURS |
    -------------------------------------------
    |'JIM'   | 4/28/2019  | 5/4/2019  |   6   |    
    |'JIM'   | 5/5/2019   | 5/11/2019 |   0   |
    |'JIM'   | 5/12/2019  | 5/18/2019 |   16  |

У меня есть функция, которая возвращает дату начала и окончания недели для каждого дня, поэтому я воспользовалась ею, присоединила ее к таблице задач по дате и суммировала часы.Это очень сближает меня, но поскольку я присоединяюсь к дате, я, очевидно, получаю NULL для USER_ID во всех строках с нулевым часом.

Текущий выход:

|USER_ID | START_DATE | END_DATE  | HOURS |
-------------------------------------------
|'JIM'   | 4/28/2019  | 5/4/2019  |   6   |    
| NULL   | 5/5/2019   | 5/11/2019 |   0   |
|'JIM'   | 5/12/2019  | 5/18/2019 |   16  |

Я пробовал несколько других подходов, но каждый раз сталкивался с одной и той же проблемой.Есть идеи?

Схема:

---------------------------------
|          TASK_LOG             |
---------------------------------    
|USER_ID | DATE_ENTERED | HOURS |
-------------------------------
|'JIM'   | 4/28/2019    |   6   |    
|'JIM'   | 5/12/2019    |   6   |
|'JIM'   | 5/13/2019    |   10  |

------------------------------------
|       DATE_HELPER_TABLE           |
|(This is actually a function, but I| 
| put it in a table to simplify)    | 
-------------------------------------    
|DATE | START_OF_WEEK | END_OF_WEEK |
-------------------------------------
|5/3/2019 | 4/28/2019  |  5/4/2019  |    
|5/4/2019 | 4/28/2019  |  5/4/2019  |
|5/5/2019 | 5/5/2019   |  5/11/2019 |
| ETC ...                           |

Запрос:

 SELECT HRS.USER_ID
        ,DHT.START_OF_WEEK
        ,DHT.END_OF_WEEK
        ,SUM(HOURS)
    FROM DATE_HELPER_TABLE DHT
    LEFT JOIN (
        SELECT TL.USER_ID
            ,TL.HOURS
            ,DHT2.START_OF_WEEK
            ,DHT2.END_OF_WEEK
        FROM TASK_LOG TL
        JOIN DATE_HELPER_TABLE DHT2 ON DHT2.DATE_VALUE = TL.DATE_ENTERED
        WHERE TL.USER_ID = 'JIM1'
        ) HRS ON HRS.START_OF_WEEK = DHT.START_OF_WEEK
    GROUP BY USER_ID
        ,DHT.START_OF_WEEK
        ,DHT.END_OF_WEEK
    ORDER BY DHT.START_OF_WEEK

http://sqlfiddle.com/#!18/02d43/3 (примечание: для этой скрипты sql я преобразовал свой помощник по датамфункция в таблицу для упрощения)

Ответы [ 3 ]

3 голосов
/ 18 мая 2019

Перекрестное объединение пользователей (в вопросе) и включение их в условие объединения. Используйте coalesce(), чтобы получить 0 вместо NULL для часов недели, когда работа не выполнялась.

SELECT u.user_id,
       dht.start_of_week,
       dht.end_of_week,
       coalesce(sum(hrs.hours), 0)
       FROM date_helper_table dht
            CROSS JOIN (VALUES ('JIM1')) u (user_id)
            LEFT JOIN (SELECT tl.user_id,
                              dht2.start_of_week,
                              tl.hours
                              FROM task_log tl
                                   INNER JOIN date_helper_table dht2
                                              ON dht2.date_value = tl.date_entered) hrs
                      ON hrs.user_id = u.user_id
                         AND hrs.start_of_week = dht.start_of_week
       GROUP BY u.user_id,
                dht.start_of_week,
                dht.end_of_week
       ORDER BY dht.start_of_week;

Я использовал предложение VALUES, чтобы перечислить пользователей. Если вы хотите узнать время только для определенных пользователей, вы можете сделать это тоже (или использовать любой другой подзапрос, или ...). В противном случае вы можете использовать свою пользовательскую таблицу (которую вы не опубликовали, поэтому мне пришлось использовать эту замену).

Однако цифры, которые получены этим (и вашим исходным запросом), выглядят странно для меня. В скрипте ваш пользователь проработал всего 23 часов в таблице task_log. Тем не менее, ваши суммы в результате составляют 24 и 80, что само по себе намного, а еще хуже, учитывая, что 1 час в task_log даже не на дату, указанную в date_helper_table.

Я подозреваю, что вы получите более точные цифры, если просто присоединитесь к task_log, а не к этой странной производной таблице.

SELECT u.user_id,
       dht.start_of_week,
       dht.end_of_week,
       coalesce(sum(tl.hours), 0)
       FROM date_helper_table dht
            CROSS JOIN (VALUES ('JIM1')) u (user_id)
            LEFT JOIN task_log tl
                      ON tl.user_id = u.user_id
                         AND tl.date_entered = dht.date_value
       GROUP BY u.user_id,
                dht.start_of_week,
                dht.end_of_week
       ORDER BY dht.start_of_week;

Но, возможно, это только я.

SQL Fiddle

1 голос
/ 18 мая 2019

http://sqlfiddle.com/#!18/02d43/65

Используя вашу скрипту SQL, я просто обновил оператор select, чтобы учесть и преобразовать нулевые значения.Насколько я могу судить, в вашем посте нет ничего, что делало бы эту опцию нежизнеспособной.Пожалуйста, дайте мне знать, если это не так, и я буду обновлять.(Это не предназначено для того, чтобы отвлекать внимание от ответа, но предлагает альтернативу)

SELECT ISNULL(HRS.USER_ID, '') as [USER_ID]
    ,DHT.START_OF_WEEK
    ,DHT.END_OF_WEEK
    ,SUM(ISNULL(HOURS,0)) as [SUM]
FROM DATE_HELPER_TABLE DHT
LEFT JOIN (
    SELECT TL.USER_ID
        ,TL.HOURS
        ,DHT2.START_OF_WEEK
        ,DHT2.END_OF_WEEK
    FROM TASK_LOG TL
    JOIN DATE_HELPER_TABLE DHT2 ON DHT2.DATE_VALUE = TL.DATE_ENTERED
    WHERE TL.USER_ID = 'JIM1'
    ) HRS ON HRS.START_OF_WEEK = DHT.START_OF_WEEK
GROUP BY USER_ID
    ,DHT.START_OF_WEEK
    ,DHT.END_OF_WEEK
ORDER BY DHT.START_OF_WEEK
0 голосов
/ 18 мая 2019

Создайте таблицу дат, которая включает все даты на следующие 100 лет в первом столбце, неделю года, день месяца и т. Д. В следующем.

Затем выберите из этой таблицы дат и оставьте присоединиться ко всему остальному. Выполните функцию isnull, чтобы заменить нули на нули.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...