Накопленная сумма последовательных рабочих дней, которая сбрасывается в 1, если последовательные дни = 0, для каждого идентификатора - PullRequest
1 голос
/ 16 февраля 2020

У меня есть 3 столбца:

Идентификатор сотрудника (числовой)

День работы (дата гггг-мм-дд, когда у сотрудника была смена)

is_consecutive_work_day ( 1, если дни работы являются последовательными, иначе 0)

Мне нужно 4-е: Consecutive_work_days (совокупная сумма is_consecutive_work_day, которая сбрасывается в 1, когда is_consecutive_work_day = 0). Так что это будет go максимум 5 для любого сотрудника ID. У некоторых будет 1,2,3, у других 1,2 ... et c.

Что мне не удается понять, так это как написать 4-й столбец (последовательность_дней). Не о том, как написать последовательную сумму для каждого сотрудника, а именно как обнулить 1, когда is_consecutive_work_day = 0 для идентификатора сотрудника.

Могу ли я попросить вашей помощи относительно этого 4-го столбца, пожалуйста? Спасибо.

Ответы [ 2 ]

2 голосов
/ 16 февраля 2020

Вы можете использовать оконные функции. lag() позволяет получить доступ к предыдущему day_of_work для того же сотрудника, которого вы можете сравнить с текущим day_of_work: если разница в один день, вы можете установить is_consecutive_work_day в 1.

select
    employee_id,
    day_of_work,
    case 
        when day_of_work 
            = lag(day_of_work) over(partition by employee_id order by day_of_work) 
                + interval 1 day
        then 1
        else 0
    end is_consecutive_work_day 
from mytable

Чтобы вычислить накопленную сумму, это немного сложнее. Мы можем использовать некоторую технику пробелов и островов, чтобы поместить каждую запись в группу, к которой она принадлежит: в основном, каждый раз, когда встречается is_consecutive_work_day из 0, начинается новая группа; затем мы можем создать окно sum() для каждой группы:

select 
    employee_id,
    day_of_work,
    is_consecutive_work_day,
    sum(is_consecutive_work_day) 
        over(partition by employee_id, grp order by day_of_work)
        consecutive_work_days 
from (
    select 
        t.*,
        sum(1 - is_consecutive_work_day) over(partition by employee_id order by day_of_work)  grp
    from (
        select
            t.*,
            case 
                when day_of_work 
                    = lag(day_of_work) over(partition by employee_id order by day_of_work) 
                        + interval 1 day
                then 1
                else 0
            end is_consecutive_work_day 
        from mytable t
    ) t
) t
0 голосов
/ 16 февраля 2020

Несмотря на то, что это похоже на проблему пропусков и островков, существует более простое решение. Просто вычислите максимальное предыдущее значение, равное 0, и возьмите разницу в дате.

Единственное предостережение, если его нет.

Это будет:

select t.*,
       datediff(day_of_work,
                coalesce(max(case when is_consecutive_work_day = 0 then day_of_work end) over (partition by employee_id),
                         date_add(min(day_of_work) partition by employee_id), 1)
                        )
               ) as fourth_column
from t;
...