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

Sauter l'écart SQL sur une condition spécifique et l'utilisation appropriée de lead()

Requête avec les fonctions de fenêtre

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0)    OVER (PARTITION BY status ORDER BY id) AS last_val
         ,lag(status, 1, 0) OVER w2 AS last_status
         ,lag(next_id)      OVER w2 AS next_id_of_last_status
   FROM  (
      SELECT *, lead(id) OVER (PARTITION BY status ORDER BY id) AS next_id
      FROM   t1
      ) AS t
   WINDOW w2 AS (PARTITION BY val ORDER BY id)
  ) x
WHERE (last_val <> val OR last_status <> status)
AND   (status = 1 
       OR last_status = 1
          AND ((next_id_of_last_status > id) OR next_id_of_last_status IS NULL)
      )
ORDER  BY id

En plus de ce que nous avions déjà , nous avons besoin d'interrupteurs OFF valides.

Un OFF basculer si valide si l'appareil a été allumé ON avant (last_status = 1 ) et le prochain ON opération après qui vient après le OFF switch en question (next_id_of_last_status > id ).

Nous devons prévoir le cas particulier où il y a eu le dernier ON opération, nous vérifions donc NULL en plus (OR next_id_of_last_status IS NULL ).

Le next_id_of_last_status vient de la même fenêtre que nous prenons last_status de. Par conséquent, j'ai introduit une syntaxe supplémentaire pour la déclaration de fenêtre explicite, afin de ne pas avoir à me répéter :

WINDOW w2 AS (PARTITION BY val ORDER BY id)

Et nous devons obtenir le prochain identifiant pour le dernier statut dans une sous-requête plus tôt (sous-requête t ).

Si vous avez tout compris ça , vous ne devriez pas avoir de problème pour taper lead() en plus de cette requête pour arriver à votre destination finale. :)

Fonction PL/pgSQL

Une fois que cela devient aussi complexe, il est temps de passer au traitement procédural.

Cette fonction plpgsql relativement simple réduit les performances de la requête de fonction de fenêtre complexe, pour la simple raison qu'elle n'a à parcourir l'ensemble de la table qu'une seule fois.

CREATE OR REPLACE FUNCTION valid_t1 (OUT t t1)  -- row variable of table type
  RETURNS SETOF t1 LANGUAGE plpgsql AS
$func$
DECLARE
   _last_on int := -1;  -- init with impossible value
BEGIN

FOR t IN
   SELECT * FROM t1 ORDER BY id
LOOP
   IF t.status = 1 THEN
      IF _last_on <> t.val THEN
         RETURN NEXT;
         _last_on := t.val;
      END IF;
   ELSE
      IF _last_on = t.val THEN
         RETURN NEXT;
         _last_on := -1;
      END IF;
   END IF;
END LOOP;

END
$func$;

Appel :

SELECT * FROM valid_t1();