PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przeskocz lukę SQL nad określonym warunkiem i właściwym użyciem lead()

Zapytanie z funkcjami okna

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

Oprócz co już mieliśmy , potrzebujemy prawidłowych wyłączników OFF.

OFF przełącznik, jeśli jest ważny, jeśli urządzenie zostało włączone ON przed (last_status = 1 ) i następny ON operacja po tym następuje po OFF przełącznik, o którym mowa (next_id_of_last_status > id ).

Musimy uwzględnić szczególny przypadek, w którym wystąpił ostatni ON operacja, więc sprawdzamy, czy NULL dodatkowo (OR next_id_of_last_status IS NULL ).

next_id_of_last_status pochodzi z tego samego okna, co last_status z. Dlatego wprowadziłem dodatkową składnię dla jawnej deklaracji okna, więc nie muszę się powtarzać:

WINDOW w2 AS (PARTITION BY val ORDER BY id)

I musimy uzyskać następny identyfikator dla ostatniego statusu w podzapytaniu wcześniej (podzapytanie t ).

Jeśli wszystko zrozumiałeś, to , nie powinieneś mieć problemu z uderzeniem w lead() na górze tego zapytania, aby dostać się do miejsca docelowego. :)

Funkcja PL/pgSQL

Kiedy robi się tak złożona, nadszedł czas, aby przejść na przetwarzanie proceduralne.

Ta stosunkowo prosta funkcja plpgsql nukuje wydajność złożonego zapytania funkcji okna z tego prostego powodu, że musi przeskanować całą tabelę tylko raz.

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

Zadzwoń:

SELECT * FROM valid_t1();



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Automatyzacja Barmana z Puppet:it2ndq/barman (część pierwsza)

  2. Testy Parallel Go wykonywane na bazie danych PostgreSQL działającej na platformie Docker

  3. Moje ulubione rozszerzenia PostgreSQL — część druga

  4. Przeszukuj zagnieżdżony/wielopoziomowy typ Postgres JSON za pomocą Active Record

  5. Jak stworzyć widok w PostgreSQL