Получить строки, которые не имеют никакой информации между двумя разами без четкого ключа - PullRequest
0 голосов
/ 31 октября 2019

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

Я пытаюсь выяснить, как зафиксировать начало транзакции, когда сотрудник не выполнил надлежащие шаги.

Процесс всегда должен начинаться с Action_Taken = 1, заканчиватьсяAction_Taken = 3, но между этими двумя должен быть третий (или более) Action_Taken (этот Action_taken может равняться любому числу, но никогда не может быть 1 или 3 снова). Проблема возникает, когда отсутствует среднее действие, и это то, что я пытаюсь захватить.

Например:

Date_time              Employee Action_Taken  Client
2019-10-01 01:21:08.000    1        1           73
2019-10-01 01:30:50.000    1        2           73
2019-10-01 01:46:21.000    1        4           73
2019-10-01 01:52:41.000    1        3           73
2019-10-03 03:24:40.000    2        1           61
2019-10-03 03:53:28.000    2        3           61
2019-10-03 04:29:15.000    2        2           61
2019-10-01 11:43:55.000    3        1           54
2019-10-01 11:47:54.000    3        2           54
2019-10-01 11:52:00.000    3        3           54
2019-10-02 05:36:27.000    1        1           76
2019-10-02 05:59:00.000    1        3           76
2019-10-03 06:18:00.000    2        1           67
2019-10-03 06:25:56.000    2        2           67
2019-10-03 06:34:34.000    2        3           67

Я ожидаю получить этот вывод, который представляет собой строки 5 и 11:

Date_time              Employee Action_Taken  Client
2019-10-03 03:24:40.000    2        1           61
2019-10-01 01:21:08.000    1        1           73

Вот что я уже пробовал:

select *, concat(convert(date, date_time), Employee, client) AS actionkey
into #Trans_Start
from #Table
where Action_Taken = 1


select *,concat(convert(date, date_time), Employee, client) AS actionkey
into #Trans_Actions
from #test
where Action_Taken = 2

select * 
from #Trans_Start as start
where start.actionkey not in (select act.actionkey from #Trans_actions  as act  where act.actionkey = start.actionkey)

Это близко к тому, что мне нужно, и выводит только одну строку:

Date_time              Employee Action_Taken  Client
2019-10-01 01:21:08.000    1        1           73

Я знаю, что эта строка выводится только из-за того, как определен мой ключ действия. Это отсутствует, потому что Сотрудник 2 закончил тем, что сделал действие, но это было с неправильной последовательностью (Они исправили свою ошибку и попытались исправить это).

Я просто не могу понять, как записать транзакцию в таблицу, если они закончили публикацию действия из правильной последовательности.

Любая помощь будет оценена, это может бытьсовершенно другой подход, чем тот, который я выбрал.

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Я бы не предположил, что кортежи сотрудник / клиент определяют группы. В реальной жизни может случиться так, что данный сотрудник обслуживает одного и того же клиента несколько раз.

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

  1. создание групп последовательных действий: для данного сотрудника / клиента новая группа запускается каждый раз при выполнении действия 1.

  2. реализует следующие элементы управления в каждой группе:

    • группа должна содержать одно и только одно действие 3
    • действие 3 должно быть последним действием в группе
    • хотя бы одно действие, отличное от 1 или 3, должноприсутствовать в группе
  3. Показать первую запись в каждой группе, которая не прошла проверку

Запрос:

select *
from (
    select 
        t.*,
        sum(case when action_taken = 3 then 1 else 0 end) 
            over(partition by employee, client, grp) cnt_3,
        sum(case when action_taken not in (1, 3) then 1 else 0 end) 
            over(partition by employee, client, grp) cnt_others,
        last_value(action_taken) 
            over(partition by employee, client, grp order by employee) last_action
    from (
        select
            t.*,
            sum(case when action_taken = 1 then 1 else 0 end) 
                over(partition by employee, client order by date_time) grp
        from mytable t
    ) t
) t
where 
    action_taken = 1
    and not (cnt_3 = 1 and last_action = 3 and cnt_others > 0)
order by employee, client, date_time

Самый внутренний подзапрос выполняет суммирование окна для идентификации групп (grp). Следующий внешний запрос подсчитывает, сколько действий 3 существует в группах, сколько других действий, и получает последнее действие. В конце концов, внешний запрос фильтрует первую запись для каждой группы и результаты проверок.

В это db fiddle с вашими примерами данных, это возвращает:

Date_time           | Employee | Action_Taken | Client | grp | cnt_3 | cnt_others | last_action
:------------------ | -------: | -----------: | -----: | --: | ----: | ---------: | ----------:
02/10/2019 05:36:27 |        1 |            1 |     76 |   1 |     1 |          0 |           3
03/10/2019 03:24:40 |        2 |            1 |     61 |   1 |     1 |          1 |           2

Обратите внимание, что дополнительные столбцы в выходных данных также указывают причину, по которой группа была помечена. В первой записи отсутствует действие другое , во второй записи последнее действие 2 вместо 3.

0 голосов
/ 31 октября 2019

Комбинации сотрудник / клиент, кажется, однозначно определяют каждую группу. Если это так, вы можете определить группы, которые имеют проблемы с использованием агрегации и имеющие:

select employee, client
from t
group by employee, client
having min(date_time) <> max(case when action_taken = 1 then date_time end) or
       max(date_time) <> min(case when action_take = 3 then date_time end) or
       sum(case when action_taken = 1 then 1 else 0 end) <> 1 or
       sum(case when action_taken = 3 then 1 else 0 end) <> 1;

Затем вы можете включить это в запрос, чтобы получить первых членов этой группы:

select t.* 
from (select t.*,
             row_number() over (partition by employee, client order by date_time) as seqnum
      from t
     ) t join
     (select employee, client
      from t
      group by employee, client
      having min(date_time) <> max(case when action_taken = 1 then date_time end) or
             max(date_time) <> min(case when action_take = 3 then date_time end) or
             sum(case when action_taken = 1 then 1 else 0 end) <> 1 or
             sum(case when action_taken = 3 then 1 else 0 end) <> 1
      ) ec
      on t.employee = ec.employee and t.client = ec.client
where seqnum = 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...