Как можно получить дату и время не вставлять в таблицу - PullRequest
0 голосов
/ 04 мая 2019

У меня есть некоторые данные, подобные этой.

with WorkingTime as(
    select 1 Userid, '2019-04-03' RegDay, '08:48' CheckIn, '18:00' CheckOut union all
    select 1 , '2019-04-05' , '08:00' , '18:00'  union all
    select 1 , '2019-04-06' , '07:48' , '18:00'  union all
    select 1 , '2019-04-09' , '08:20' , '18:00'  
)

Теперь я хочу посчитать DateOff для UserId 1.

select Userid
     ,sum(case when CheckIn < '08:00' then 1 else 0 end) as TotalLate
     ,'?' as TotalDateOff 
from WorkingTime 
where RegDay between '2019-04-03' and '2019-04-11'
group by Userid

Дата от '2019-04-03' до '2019-04-11 »- это« 2019-04-04 »,« 2019-04-07 »,« 2019-04-10 »,« 2019-04-11 ».Этот средний столбец TotalDateOff равен 4. Как я могу достичь, как это?

Ответы [ 3 ]

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

Одним из методов является использование CTE для получения списка дат (от - до), который будет инкрементным по дням или месяцам или любым дополнительным методом, который требуется.

Вы можете использовать его в текущем CTE, добавив его к текущему, который получит минимальную дату и увеличится на 1 день, пока не достигнет максимальной даты.Затем все, что вам нужно, это простое левое соединение, которое объединит даты, если дата не существует в WorkingTime, она будет иметь значение NULL.Затем все, что вам нужно, это просто посчитать эти нули, чтобы получить итоговую дату.

Пример:

;with WorkingTime as(
    select 1 Userid, '2019-04-03' RegDay, '08:48' CheckIn, '18:00' CheckOut union all
    select 1 , '2019-04-05' , '08:00' , '18:00'  union all
    select 1 , '2019-04-06' , '07:48' , '18:00'  union all
    select 1 , '2019-04-09' , '08:20' , '18:00'  
) , WorkingOff AS (
    SELECT Userid, CAST(MIN(RegDay) AS DATE) MinRegDay
    FROM WorkingTime
    GROUP BY Userid
    UNION ALL 
    SELECT Userid,  DATEADD(DAY, 1, MinRegDay)
    FROM WorkingOff
    WHERE 
        DATEADD(DAY, 1, MinRegDay) < '2019-04-11'
) 
SELECT 
    wf.Userid
,   SUM(CASE WHEN wt.CheckIn < '08:00' THEN 1 ELSE 0 END) TotalLate
,   SUM(CASE WHEN wt.RegDay IS NULL THEN 1 ELSE 0 END) TotalDateOff 
FROM WorkingOff wf
LEFT JOIN WorkingTime wt ON wf.MinRegDay = wt.RegDay AND wf.Userid = wt.Userid
where wf.MinRegDay between '2019-04-03' and '2019-04-11'
GROUP BY wf.Userid
1 голос
/ 04 мая 2019

Для Postgres это можно сделать с помощью generate_series(), чтобы сгенерировать список дат для каждого идентификатора пользователя и использования в левом соединении:

with workingtime (userid, regday, checkin, checkout) as(
  values
    (1, date '2019-04-03', '08:48'::time, '18:00'::time),
    (1, date '2019-04-05', '08:00'::time, '18:00'::time),
    (1, date '2019-04-06', '07:48'::time, '18:00'::time),
    (1, date '2019-04-09', '08:20'::time, '18:00'::time),  
    (1, date '2019-04-10', '08:00'::time, '18:00'::time),

    (2, date '2019-04-03', '08:48'::time, '18:00'::time),
    (2, date '2019-04-06', '07:00'::time, '18:00'::time),
    (2, date '2019-04-08', '07:48'::time, '18:00'::time),
    (2, date '2019-04-09', '08:20'::time, '18:00'::time)
), ranges as (
   select w.userid, dt.day::date as regdate
   from (
     select distinct userid
     from workingtime
   ) w
     cross join generate_series(date '2019-04-03', date '2019-04-11', interval '1 day') as dt(day)
)
select r.userid,  
       count(*) filter (where checkin < '08:00') as total_late,
       count(*) filter (where wt.regday is null) as total_days_off
from ranges r
  left join workingtime wt on wt.userid = r.userid and wt.regday = r.regdate
group by r.userid
order by r.userid;

Вышеуказанное возвращает:

userid | total_late | total_days_off
-------+------------+---------------
     1 |          1 |              4
     2 |          2 |              5
0 голосов
/ 04 мая 2019

Для добавления данных необходим источник данных. В этом случае вам нужен источник, который имеет все возможные даты. Это распространенная проблема, которая принимает несколько форм - в вашем случае вы должны создать таблицу для всех дат, а затем вы пытаетесь найти то, что там, а не здесь. Например таблица календаря.

Другое использование для такой таблицы - определение финансового года, финансового квартала, возможно, праздников и т. Д.

Вы также можете создать такой [источник] с помощью функции, которую вы можете вызывать из предложения, - но самый лучший и простой вариант - это, вероятно, иметь таблицу. Вы можете создать его за 1000 лет и все готово!

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