PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Fonction avance/retard conditionnelle PostgreSQL ?

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 :

  1. Le FILTER La clause elle-même ne peut fonctionner qu'avec les valeurs de la ligne actuelle.

  2. Plus important encore, FILTER n'est pas implémenté pour les fonctions authentiques pures comme lead() ou lag() (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