Berechnete / berechnete / virtuelle / abgeleitete Spalten in PostgreSQL

113

Unterstützt PostgreSQL berechnete / berechnete Spalten wie MS SQL Server? Ich kann nichts in den Dokumenten finden, aber da diese Funktion in vielen anderen DBMS enthalten ist, dachte ich, dass mir möglicherweise etwas fehlt.

Beispiel: http://msdn.microsoft.com/en-us/library/ms191250.aspx

Mike Chamberlain
quelle
Mit dem seitlichen Unterabfrageausdruck (Postgres-Funktion) können Sie jeder Zeile problemlos weitere Spalten hinzufügen.
Victor

Antworten:

139

Bis zu Postgres 11 generierte Spalten werden nicht unterstützt - wie im SQL-Standard definiert und von einigen RDBMS implementiert, einschließlich DB2, MySQL und Oracle. Auch nicht die ähnlichen "berechneten Spalten" von SQL Server.

STOREDgenerierte Spalten werden mit Postgres 12 eingeführt . Triviales Beispiel:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> hier fummeln

VIRTUALGenerierte Spalten können mit einer der nächsten Iterationen kommen. (Noch nicht in Postgres 13).

Verbunden:


Bis dahin können Sie VIRTUALgenerierte Spalten mit einer Funktion unter Verwendung der Attributnotation ( tbl.col) emulieren, die einer virtuell generierten Spalte ähnelt und funktioniert . Das ist eine Seltsamkeit der Syntax, die in Postgres aus historischen Gründen existiert und zufällig zum Fall passt. Diese verwandte Antwort enthält Codebeispiele :

Der Ausdruck (sieht aus wie eine Spalte) ist jedoch nicht in a enthalten SELECT * FROM tbl. Sie müssen es immer explizit auflisten.

Kann auch mit einem passenden Ausdrucksindex unterstützt werden - vorausgesetzt, die Funktion ist IMMUTABLE. Mögen:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

Alternativen

Alternativ können Sie ähnliche Funktionen mit a implementieren VIEW, optional gekoppelt mit Ausdrucksindizes. Dann SELECT *kann die generierte Spalte enthalten sein.

"Persisted" ( STORED) berechnete Spalten können mit Triggern auf funktional identische Weise implementiert werden.

Materialisierte Ansichten sind ein eng verwandtes Konzept, das seit Postgres 9.3 implementiert wurde .
In früheren Versionen können MVs manuell verwaltet werden.

Erwin Brandstetter
quelle
Abhängig davon, wie viele Daten Sie gleichzeitig laden. Der Trigger kann die Dinge drastisch verlangsamen. Vielleicht möchten Sie stattdessen Updates in Betracht ziehen.
Sam Yi
1
Diese Lösungen sind bei der Migration von Oracle zu Postgres so gut wie nutzlos (ohne große Codeänderungen an einer Codebasis ohne Testfälle). Gibt es Lösungen aus Sicht der Migration?
Happybuddha
@happybuddha: Bitte stellen Sie Ihre Frage als Frage. Kommentare sind nicht der richtige Ort. Sie können jederzeit einen Link zu dieser Frage für den Kontext erstellen (und hier einen Kommentar hinzufügen, um meine Aufmerksamkeit zu erhalten und auf die zugehörige Frage zu verlinken).
Erwin Brandstetter
4
Die Funktionalität befindet sich derzeit
r90t
1
@cryanbhu: Hängt von den Details Ihres Setups und den Anforderungen ab. Möglicherweise stellen Sie eine neue Frage mit den erforderlichen Informationen.
Erwin Brandstetter
32

Ja, du kannst!! Die Lösung sollte einfach, sicher und performant sein ...

Ich bin neu in postgresql, aber es scheint, dass Sie berechnete Spalten mithilfe eines Ausdrucksindex erstellen können, der mit einer Ansicht gepaart ist (die Ansicht ist optional, erleichtert aber das Leben ein wenig).

Angenommen, meine Berechnung lautet md5(some_string_field), dann erstelle ich den Index wie folgt :

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

Bei allen Abfragen, die bearbeitet werden, MD5(some_string_field)wird der Index verwendet, anstatt ihn von Grund auf neu zu berechnen. Beispielsweise:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

Sie können dies mit EXPLAIN überprüfen .

An diesem Punkt verlassen Sie sich jedoch darauf, dass Benutzer der Tabelle genau wissen, wie die Spalte erstellt wird. Um das Leben zu vereinfachen, können Sie VIEWeine erweiterte Version der Originaltabelle erstellen und den berechneten Wert als neue Spalte hinzufügen:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

Jetzt können alle verwendeten Abfragen verwendet some_table_augmentedwerden, some_string_field_md5ohne sich Gedanken darüber zu machen, wie es funktioniert. Sie erhalten nur eine gute Leistung. Die Ansicht kopiert keine Daten aus der Originaltabelle, ist also sowohl speicher- als auch leistungsmäßig gut. Beachten Sie jedoch, dass Sie nicht in eine Ansicht aktualisieren / einfügen können, sondern nur in die Quelltabelle. Wenn Sie dies jedoch wirklich möchten, können Sie Einfügungen und Aktualisierungen mithilfe von Regeln in die Quelltabelle umleiten (in diesem letzten Punkt könnte ich mich irren) Ich habe es selbst nie versucht.

Bearbeiten: Wenn die Abfrage konkurrierende Indizes umfasst, verwendet die Planer-Engine den Ausdrucksindex manchmal überhaupt nicht. Die Wahl scheint datenabhängig zu sein.

Dan-Mann
quelle
1
Könnten Sie bitte erklären oder ein Beispiel geben if the query involves competing indices?
dvtan
17

Eine Möglichkeit, dies zu tun, ist mit einem Auslöser!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

Der Trigger wird ausgelöst, bevor die Zeile aktualisiert oder eingefügt wird. Es ändert das Feld, das wir für den NEWDatensatz berechnen möchten, und gibt dann diesen Datensatz zurück.

Elmer
quelle
Wann wird der Abzug akut ausgelöst? Ich habe das oben genannte ausgeführt und dies getan insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;und es ist gerade zurückgekehrt: 1 2 und 4 8
happybuddha
2
versuchen Sie, insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;der Wert der twoSpalte wird automatisch berechnet!
Elmer
8

PostgreSQL 12 unterstützt generierte Spalten:

PostgreSQL 12 Beta 1 veröffentlicht!

Generierte Spalten

PostgreSQL 12 ermöglicht die Erstellung generierter Spalten, die ihre Werte mit einem Ausdruck unter Verwendung des Inhalts anderer Spalten berechnen. Diese Funktion bietet gespeicherte generierte Spalten, die bei Einfügungen und Aktualisierungen berechnet und auf der Festplatte gespeichert werden. Virtuell generierte Spalten, die nur berechnet werden, wenn eine Spalte als Teil einer Abfrage gelesen wird, sind noch nicht implementiert.


Generierte Spalten

Eine generierte Spalte ist eine spezielle Spalte, die immer aus anderen Spalten berechnet wird. Daher ist es für Spalten eine Ansicht für Tabellen.

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> Geigen-Demo

Lukasz Szozda
quelle
1

Ich bin mir nicht sicher, ob Sie das meinen, aber Posgres unterstützt normalerweise die "Dummy" -ETL-Syntax. Ich habe eine leere Spalte in der Tabelle erstellt und musste sie dann mit berechneten Datensätzen füllen, abhängig von den Werten in der Zeile.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. Es ist so blöd, dass ich vermute, dass es nicht das ist, wonach Sie suchen.
  2. Offensichtlich ist es nicht dynamisch, Sie führen es einmal aus. Aber kein Hindernis, um es in den Abzug zu bringen.
ďobo
quelle
0

Ich habe einen Code, der funktioniert und den berechneten Begriff verwendet. Ich bin nicht auf PostgresSQL rein, obwohl wir auf PADB laufen

Hier ist, wie es verwendet wird

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;
Wired604
quelle
Was ist PADB genau?
Gherman
ParAccel Analytic Database ist alt, aber schön ... en.wikipedia.org/wiki/ParAccel
Wired604
Aber wie hängt es mit einer Frage zu Postgres zusammen? Sicher gibt es viele DBs mit Unterstützung für berechnete Spalten.
Gherman
Es tut mir leid, dass ich mir nicht die Zeit genommen habe, wieder in den Kontext zurückzukehren. PADB basiert auf Postgress!
Wired604
-6

Eine leichte Lösung mit Check-Einschränkung:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
cinereo
quelle
6
Wie hängt das mit dem Konzept einer berechneten Spalte zusammen? Möchten Sie das erklären?
Erwin Brandstetter
4
Einverstanden, es ist nicht direkt verwandt. Aber es ist ein Ersatz für einen einfachen Fall, wenn Sie nur so etwas tun müssen field as 1 persisted.
Cinereo
2
Eine Beschreibung wäre in der Tat schön gewesen. Ich denke, diese Antwort lautet: Wenn die Berechnung mit der Standardklausel durchgeführt werden kann, können Sie eine Standard- und eine Prüfbedingung verwenden, um zu verhindern, dass jemand den Wert ändert.
Ross Bradbury
@ Ross Bradbury: Einverstanden, aber das funktioniert nur zum Einfügen. Es würde nicht funktionieren, wenn eine abhängige Spalte aktualisiert würde.
Stefan Steiger