Votre définition :
l'activité du groupe B a toujours lieu après l'activité du groupe A.
.. implique logiquement qu'il y a, par utilisateur, 0 ou 1 activité B après 1 ou plusieurs activités A. Jamais plus de 1 B d'activités consécutives.
Vous pouvez le faire fonctionner avec une fonction de fenêtre unique, DISTINCT ON et CASE , qui devrait être le moyen le plus rapide pour peu lignes par utilisateur (voir également ci-dessous) :
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<>jouez ici
Un CASE SQL l'expression par défaut est NULL si non ELSE branche est ajoutée, j'ai donc été bref.
En supposant time est défini NOT NULL . Sinon, vous pouvez ajouter NULLS LAST . Pourquoi ?
- Trier par colonne ASC, mais les valeurs NULL en premier ?
(activity LIKE 'A%' OR activity LIKE 'B%') est plus verbeux que activity ~ '^[AB]' , mais généralement plus rapide dans les anciennes versions de Postgres. À propos de la correspondance de modèles :
- Mise en correspondance de modèles avec LIKE, SIMILAR TO ou des expressions régulières dans PostgreSQL
Fonctions de fenêtre conditionnelle ?
C'est en fait possible . Vous pouvez combiner l'agrégat FILTER clause avec le OVER clause des fonctions de fenêtre. Cependant :
-
Le
FILTERLa clause elle-même ne peut fonctionner qu'avec les valeurs de la ligne actuelle. -
Plus important encore,
FILTERn'est pas implémenté pour les fonctions authentiques pures commelead()oulag()(jusqu'à Postgres 13) - uniquement pour les fonctions d'agrégation.
Si vous essayez :
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Postgres vous dira :
FILTER is not implemented for non-aggregate window functions
À propos de FILTER :
- Colonnes agrégées avec des filtres supplémentaires (distincts)
- Référence à la ligne actuelle dans la clause FILTER de la fonction de fenêtre
Performances
Pour quelques utilisateurs avec peu lignes par utilisateur, à peu près toutes la requête est rapide, même sans index.
Pour beaucoup utilisateurs et peu lignes par utilisateur, la première requête ci-dessus devrait être la plus rapide. Voir :
- Sélectionner la première ligne de chaque groupe GROUP BY ?
Pour beaucoup lignes par utilisateur, il y a (potentiellement beaucoup ) techniques plus rapides, en fonction des détails de votre configuration. Voir :
- Optimiser la requête GROUP BY pour récupérer la dernière ligne par utilisateur