Vaše definice:
aktivita ze skupiny B probíhá vždy po aktivitě ze skupiny A.
.. logicky znamená, že na uživatele připadá 0 nebo 1 aktivita B po 1 nebo více aktivitách A. Nikdy více než 1 B aktivity za sebou.
Můžete to zprovoznit pomocí funkce jednoho okna, DISTINCT ON
a CASE
, což by měl být nejrychlejší způsob pro málo řádků na uživatele (viz také níže):
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<>zde hrajte
CASE
SQL výchozí hodnota výrazu je NULL
pokud není ELSE
větev je přidána, takže jsem to zkrátil.
Za předpokladu time
je definováno NOT NULL
. Jinak možná budete chtít přidat NULLS LAST
. Proč?
- Seřadit podle sloupce ASC, ale nejprve hodnoty NULL?
(activity LIKE 'A%' OR activity LIKE 'B%')
je podrobnější než activity ~ '^[AB]'
, ale obvykle rychlejší ve starších verzích Postgres. O shodě vzorů:
- Shoda vzoru s LIKE, SIMILAR TO nebo regulárními výrazy v PostgreSQL
Podmíněné funkce okna?
To je vlastně možné . Souhrnný FILTER
můžete kombinovat klauzule s OVER
klauzule okenních funkcí. Nicméně :
-
FILTER
samotná klauzule může pracovat pouze s hodnotami z aktuálního řádku. -
A co je důležitější,
FILTER
není implementován pro čistě originální funkce jakolead()
nebolag()
(až do Postgres 13) – pouze pro agregační funkce.
Pokud to zkusíte:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Postgres vám řekne:
FILTER is not implemented for non-aggregate window functions
O FILTER
:
- Agregujte sloupce pomocí dalších (odlišných) filtrů
- Odkaz na aktuální řádek v klauzuli FILTER funkce okna
Výkon
Pro málo uživatelé s málo řádků na uživatele, v podstatě libovolné dotaz je rychlý, i bez indexu.
Pro mnoho uživatelů a několika řádků na uživatele, první výše uvedený dotaz by měl být nejrychlejší. Viz:
- Vybrat první řádek v každé skupině GROUP BY?
Pro mnoho řádků na uživatele, existuje (potenciálně hodně ) rychlejší techniky, v závislosti na podrobnostech vašeho nastavení. Viz:
- Optimalizujte dotaz GROUP BY pro načtení posledního řádku na uživatele