Ваше определение:
активность из группы B всегда происходит после активности из группы A.
.. логически подразумевает, что для каждого пользователя существует 0 или 1 активность B после 1 или более операций A. Не более 1 млрд действий подряд.
Вы можете заставить его работать с помощью функции единого окна, DISTINCT ON
и CASE
, что должно быть самым быстрым способом для нескольких строк на пользователя (также см. Ниже):
SELECT name
, CASE WHEN a2 LIKE 'B%' THEN a1 ELSE a2 END AS activity
, CASE WHEN a2 LIKE 'B%' THEN a2 END AS next_activity
FROM (
SELECT DISTINCT ON (name)
name
, lead(activity) OVER (PARTITION BY name ORDER BY time DESC) AS a1
, activity AS a2
FROM t
WHERE (activity LIKE 'A%' OR activity LIKE 'B%')
ORDER BY name, time DESC
) sub;
db ‹› fiddle здесь
По умолчанию выражение SQL CASE
равно NULL
, если ветка ELSE
не добавлена, поэтому я остановился на этом кратко.
Предполагая, что time
определен NOT NULL
. В противном случае вы можете добавить NULLS LAST
. Почему?
(activity LIKE 'A%' OR activity LIKE 'B%')
более подробный, чем activity ~ '^[AB]'
, но обычно быстрее в старых версиях Postgres. О сопоставлении с образцом:
Условные оконные функции?
Это действительно возможно. Вы можете комбинировать агрегатное предложение FILTER
с предложением OVER
оконных функций. Однако:
Само предложение FILTER
может работать только со значениями из текущей строки.
Что еще более важно, FILTER
не реализован для чистых подлинных функций, таких как lead()
или lag()
(до Postgres 13) - только для агрегатные функции.
Если вы пытаетесь:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Postgres скажет вам:
FILTER is not implemented for non-aggregate window functions
О FILTER
:
Представление
Для нескольких пользователей с несколькими строками на пользователя почти любой запрос выполняется быстро. , даже без индекса.
Для многих пользователей и нескольких строк на пользователя первый запрос выше должен быть самым быстрым. Видеть:
Для множества строк на пользователя существуют (потенциально намного) более быстрые методы, в зависимости от деталей вашей настройки. Видеть:
person
Erwin Brandstetter
schedule
22.01.2017
activity from group B always takes place after activity from group A
. Это означает, что у каждого пользователя никогда не бывает двух последовательных действий B? Также: ваши образцы данных показывают, что все действия для каждого пользователя всегда происходят последовательно, то есть A1 - ›A2 -› A3, .. никогда A3 - ›A2. Верный? И: версия Postgres? - person Erwin Brandstetter   schedule 23.01.2017