PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

So verwenden Sie eine Ringdatenstruktur in Fensterfunktionen

  • Verwenden Sie COALESCE wie von @Justin bereitgestellt.
  • Mit first_value() / last_value() Sie brauchen um ein ORDER BY hinzuzufügen -Klausel zur Fensterdefinition oder die Reihenfolge ist undefiniert . In diesem Beispiel haben Sie einfach Glück gehabt, weil die Zeilen direkt nach dem Erstellen der Dummy-Tabelle in der richtigen Reihenfolge sind.
    Sobald Sie ORDER BY hinzufügen , endet der Standardfensterrahmen an der aktuellen Zeile , und Sie müssen den last_value() mit einem Sonderfall versehen aufrufen - oder die Sortierreihenfolge im Fensterrahmen umkehren, wie in meinem ersten Beispiel gezeigt.

  • Bei mehrfacher Wiederverwendung einer Fensterdefinition wird explizit ein WINDOW -Klausel vereinfacht die Syntax erheblich:

SELECT ring, part, ARRAY[
          coalesce(
             lag(part) OVER w
            ,first_value(part) OVER (PARTITION BY ring ORDER BY part DESC))
         ,part
         ,coalesce(
             lead(part) OVER w
            ,first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring ORDER BY part);

Noch besser , dieselbe Fensterdefinition wiederverwenden, sodass Postgres alle Werte in einem einzigen Scan berechnen kann. Damit dies funktioniert, müssen wir einen benutzerdefinierten Fensterrahmen definieren :

SELECT ring, part, ARRAY[
          coalesce(
             lag(part) OVER w
            ,last_value(part) OVER w)
         ,part
         ,coalesce(
             lead(part) OVER w
            ,first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring
             ORDER BY part
             RANGE BETWEEN UNBOUNDED PRECEDING
                       AND UNBOUNDED FOLLOWING)
ORDER  BY 1,2;

Sie können sogar die Rahmendefinition für jeden Fensterfunktionsaufruf anpassen:

SELECT ring, part, ARRAY[
          coalesce(
             lag(part) OVER w
            ,last_value(part) OVER (w RANGE BETWEEN CURRENT ROW
                                                AND UNBOUNDED FOLLOWING))
         ,part
         ,coalesce(
             lead(part) OVER w
            ,first_value(part) OVER w)
         ] AS neighbours
FROM   rp
WINDOW w AS (PARTITION BY ring ORDER BY part)
ORDER  BY 1,2;

Kann bei Ringen mit vielen Teilen schneller sein. Sie müssen testen.

SQL-Geige Demonstration aller drei mit einem verbesserten Testfall. Ziehen Sie Abfragepläne in Betracht.

Mehr über Fensterrahmendefinitionen:

  • Im Handbuch.
  • PostgreSQL-Fensterfunktion:Partition durch Vergleich
  • PostgreSQL-Abfrage mit maximalem und minimalem Datum plus zugehöriger ID pro Zeile