PostgreSQL: Generierte Spalten

16

Unterstützt PostgreSQL generierte Spalten ? Auch als virtuelle Spalten bekannt . Ich spreche nicht über IDENTITYSpalten .

Ich kann keine Informationen zu dieser bemerkenswerten Funktion finden, aber ich weiß, dass sie auf SQL Server und in den neuesten Versionen von MariaDB & MySQL verfügbar ist.

Die Funktion ist im SQL: 2003- Standard erwähnt, und es gab einige Diskussionen in den PostgreSQL-Foren um 2006, aber ich kann in dieser Angelegenheit nichts Wesentliches finden.

Es gibt einige Diskussionen über SO, aber es ist schon ziemlich alt, so dass es möglicherweise nicht mehr aktuell ist.

Manngo
quelle
2
Diese verwandte Antwort von 2012 auf SO kann hilfreich sein: stackoverflow.com/questions/11165450/… Immer noch gültig.
Erwin Brandstetter
@ErwinBrandstetter Sorry, ich habe diesen Kommentar verpasst. Es ist ein nützlicher Trick. Vielen Dank.
Manngo

Antworten:

17

Sie sind sich nicht sicher, ob Sie dies möchten, aber Attribut- row.full_nameund Funktionsnotation full_name(row)sind in postgresql gleichwertig.

Das heißt, Sie nehmen einen Tisch

CREATE TABLE people (
  first_name text,
  last_name text
);

und eine Funktion:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

und nenne es so:

select full_name from people

Brauchen Sie das?

Um die Dinge zu beschleunigen, können Sie einen Ausdrucksindex erstellen:

CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));

Oder speichern Sie alles in einer materialisierten Ansicht.

Beispiel hier entnommen: http://bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/

Fabian Zeindl
quelle
2
Das ist die richtige Antwort. Siehe beispielsweise, wie Postgrest dieses Verhalten als "berechnete Spalten" bezeichnet.
Fiatjaf
Tippfehler, denke ich - die Auswahl sollte von select people.full_name from peopleoder sein select full_name(people) from people?
Barguast
Nein, das funktioniert so. Das Präfix in "select people.full_name from people" kann wie in regulärem SQL weggelassen werden.
Fabian Zeindl
Ich habe diese Antwort verpasst und bin sozusagen gekommen, lange nachdem ich aufgegeben hatte. Danke für den Vorschlag.
Manngo
1
Könnten Sie die akzeptierte Antwort dann ändern?
Fabian Zeindl
6

Nein, dies wird derzeit (ab Postgres 9.6) nicht unterstützt.

Die einzige Problemumgehung besteht darin, einen Trigger oder eine Ansicht zu verwenden, wenn es sich um eine einfache Berechnung handelt, die Sie nicht indizieren müssen.

ein Pferd ohne Name
quelle
Ratten. Ich nehme an, ich könnte eine materialisierte Sichtweise anstreben, wenn ich die Aufführung brauche. Ich habe eine Anfrage für das Feature hinzugefügt, da es bereits im Wettbewerb verfügbar ist.
Manngo
1
MVIEW ist nicht erforderlich. Mit einer Spalte mit einem Auslöser können Sie auch den Inhalt der Spalte indizieren
a_horse_with_no_name
Ich habe ein philosophisches Problem mit dem Speichern zusätzlicher realer Spalten, die im Grunde eine Wiederholung der anderen Daten sind. Es normalisiert die Tabelle.
Manngo
5
Nun, eine berechnete Spalte ist genau das: Speichern von de-normalisierten Daten. Es spielt keine Rolle, wie der Wert der berechneten Spalte generiert wird. Ich sehe keinen konzeptionellen Unterschied zwischen einer "echten" berechneten Spalte und einer Spalte, die durch einen Trigger generiert wird
a_horse_with_no_name
Eine andere Problemumgehung (in einigen Fällen) besteht darin, einen Ausdruck zu indizieren.
Ypercubeᵀᴹ
5

Ja: GENERATED ALWAYS AS … STORED

Postgres 12 fügt die Funktionalität für generierte Spalten hinzu, wie im SQL: 2003- Standard erwähnt.

Der Wert wird zum Zeitpunkt eines INSERToder generiert UPDATEund dann wie jeder andere Wert in der Zeile gespeichert.

Ein generiertes muss auf einer Basisspalte derselben Tabelle oder auf einer unveränderlichen Funktion basieren .

Die Syntax ist einfach, eine Klausel über CREATE TABLE:

GENERATED ALWAYS AS ( generation_expr ) STORED 

Beispiel:

CREATE TABLE people (
    ...,
    height_cm NUMERIC,
    height_in NUMERIC GENERATED ALWAYS AS ( height_cm / 2.54 ) STORED
);

Eigenschaften:

  • Kann indiziert werden.
  • Teil des SQL-Standards.

Vorsichtsmaßnahmen:

  • Basierend auf Spalten derselben Tabelle (nicht verwandte Tabellen)
  • Nicht für die Partitionierung zulässig (kann nicht Teil eines Partitionsschlüssels sein)
  • Daten werden immer in die Zeile geschrieben und belegen Speicherplatz
    • Die zukünftige Funktion bietet möglicherweise VIRTUAL für Werte, die im laufenden Betrieb ohne Speicherung berechnet werden
  • Single-Generation Deep (Basisspalte verwenden, keine andere generierte Spalte)
  • Es gibt keine GENERATED BY DEFAULT (Wert kann nicht überschrieben werden)
  • In BEFORE-Trigger kann nicht auf gen-col zugegriffen werden (Wert noch nicht bestimmt)
  • Funktionen müssen unveränderlich sein

Sehen:

Basil Bourque
quelle
Danke für diese Information. Ich sehe, dass Version 12 noch nicht vollständig freigegeben ist, freue mich aber darauf. Ich stelle fest, dass PostgreSQL die Standard-Syntax verwendet, ansonsten aber mit MSSQL identisch ist. Die SQL2003-Spezifikationen habe ich hier gefunden: sigmodrecord.org/publications/sigmodRecord/0403/… . Ich habe immer gesagt, dass SQL ein sich sehr langsam bewegender Standard ist und dass DBMS-Implementierungen sogar langsam sind.
Manngo
0

Abhängig von Ihrem Anwendungsfall können Sie ein solches Verhalten erzielen, indem Sie eine neue Spalte deklarieren und beim Einfügen / Aktualisieren einen Auslöser hinzufügen.

Ich würde die obigen Antworten nach Möglichkeit verwenden, um zu vermeiden, dass Daten dupliziert werden, die aus Ihren bereits vorhandenen Daten abgeleitet werden könnten, aber dies reicht aus und könnte für rechenintensive abgeleitete Felder nützlich sein, die Sie einmal berechnen und speichern möchten.

Ich habe diesen Ansatz in Betracht gezogen, um ein Problem zu lösen, bei dem ich manchmal nur 15 Ziffern eines 18-stelligen Schlüssels hatte (die letzten 3 Ziffern sind nur eine Prüfsumme), aber in der Lage sein wollte, eine Fremdschlüsselbeziehung durchzusetzen.

PG-Dokumente zu Triggern: https://www.postgresql.org/docs/9.6/sql-createtrigger.html

W3-Beispiel: https://www.w3resource.com/PostgreSQL/postgresql-triggers.php

Allen Phelps
quelle