(SQL) Как выполнить условную фильтрацию на основе значения, рассчитанного с использованием OVER

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

Во-первых: я хочу отфильтровать клиентов, которые не начали, перейдя в первое состояние в начале рабочего процесса (введите состояние 0).

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

В каждой записи есть:

  • CUSTOMER_ID (целое число)
  • СОСТОЯНИЕ (целое число)
  • ДЕЙСТВИЕ (вход или выход из этого состояния, varchar)
  • UPDATE_DT (отметка времени записи)

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

SELECT
    CUSTOMER_ID,
    STATE,
    MIN(UPDATE_DT) AS ENTRY_DATE,
    MAX(UPDATE_DT) AS EXIT_DATE
FROM LOG_DATA
GROUP BY CUSTOMER_ID, STATE
ORDER BY CUSTOMER_ID, STATE;

Но сразу сталкиваюсь с несколькими проблемами. Запрос будет выполнен нормально, но:

  • Я не удалял клиентов, которые не начали с перехода в состояние 0
  • Не все клиенты гарантированно имеют дату входа и выхода для каждого штата, поэтому иногда мои MIN / MAX не срабатывают.

Я попытался сосредоточиться на первой проблеме, добавив в свой выбор дополнительный атрибут следующим образом:

MIN(STATE) OVER(PARTITION BY CUSTOMER_ID) AS EARLIEST_STATE

Но потом столкнулся с несколькими проблемами. Я не могу включить EARLIEST_STATE в качестве условия WHERE или GROUP BY HAVING, потому что для WHERE он не существует, а GROUP BY не позволяет мне включать EARLIEST_STATE.

Как я и думал, ситуация становится еще хуже - MIN (STATE) может только доказать, в лучшем случае, что клиент имеет STATE = 0, но не то, что у него есть запись, которая говорит ACTION = "enter" и STATE = 0. Таким образом, этот подход не только терпит неудачу. потому что я не могу заставить его работать, но и потому, что это тоже логически неверно.

Я знаю, что могу сделать несколько SELECT с помощью SELECT, но это кажется неуклюжим, и я хочу узнать, как это сделать правильно. Также не помогает то, что я имею дело с 10 миллионами строк данных, поэтому эффективность важна.

Я использую Postgres 9.5, я не контролирую ни технологию БД, ни схему данных в этом случае.

Это было бы медленно, но я мог бы использовать для этого что-нибудь на моем Python, но мне бы очень хотелось знать, как это сделать с помощью БД.

Примеры данных и желаемые результаты помогут В самом деле!

Gordon Linoff 08.06.2018 20:38
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
1
18
1

Ответы 1

Если я правильно понимаю, вам нужна хотя бы одна строка с Action = 'Enter' и state = 0 для любого клиента, который находится в наборе результатов. Это предполагает оконную функцию:

SELECT CUSTOMER_ID, STATE,
       MIN(UPDATE_DT) AS ENTRY_DATE,
       MAX(UPDATE_DT) AS EXIT_DATE,
FROM (SELECT l.*,
             SUM(CASE WHEN ACTION = 'Enter' AND state = 0 THEN 1 ELSE 0 END) OVER (PARTITION BY CUSTOMER_ID) as num_validenter
      FROM LOG_DATA l
     ) l
WHERE num_validenter > 0
GROUP BY CUSTOMER_ID, STATE
ORDER BY CUSTOMER_ID, STATE

Другие вопросы по теме