sql >> Base de Datos >  >> RDS >> PostgreSQL

Salte la brecha de SQL sobre la condición específica y el uso adecuado de plomo ()

Consulta con funciones de ventana

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

Además de lo que ya teníamos , necesitamos interruptores de APAGADO válidos.

Un OFF cambiar si es válido si el dispositivo se encendió ON antes (last_status = 1 ) y el siguiente ON operación después de que viene después del OFF interruptor en cuestión (next_id_of_last_status > id ).

Tenemos que prever el caso especial de que haya sido el último ON operación, por lo que buscamos NULL además (OR next_id_of_last_status IS NULL ).

El next_id_of_last_status proviene de la misma ventana que tomamos last_status de. Por lo tanto, introduje una sintaxis adicional para la declaración de ventana explícita, por lo que no tengo que repetirme:

WINDOW w2 AS (PARTITION BY val ORDER BY id)

Y necesitamos obtener la siguiente identificación para el último estado en una subconsulta anterior (subconsulta t ).

Si has entendido todo eso , no debería tener problemas para abofetear lead() además de esta consulta para llegar a su destino final. :)

Función PL/pgSQL

Una vez que se vuelve tan complejo, es hora de cambiar al procesamiento procesal.

Esta comparativamente simple función plpgsql destruye el rendimiento de la consulta de función de ventana compleja, por la sencilla razón de que tiene que escanear toda la tabla solo una vez.

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$;

Llamar:

SELECT * FROM valid_t1();