it-swarm.com.de

Berechnete/berechnete/virtuelle/abgeleitete Spalten in PostgreSQL

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 etwas fehlt.

ZB: http://msdn.Microsoft.com/de-de/library/ms191250.aspx

62

Bis zu Postgres 11 generierte Spalten werden nicht unterstützt - wie im SQL-Standard definiert und in einigen RDBMS einschließlich DB2, MySQL und Oracle implementiert. Noch das ähnliche "berechnete Spalten" von SQL Server.

Das Feature ist in Entwicklung für Postgres 12 , Hauptautor Peter Eisentraut.

Für jetzt können Sie mit einer -Funktion mit Attributnotation (tbl.col) emulieren, dass wie eine virtuell erzeugte Spalte aussieht und funktioniert. Das ist ein bisschen eine seltsame Syntax, die aus historischen Gründen in Postgres existiert und die in den Fall passt. Diese verwandte Antwort enthält code-Beispiele:

Der Ausdruck (der wie eine Spalte aussieht) ist jedoch nicht in einem SELECT * FROM tbl enthalten. 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 eine ähnliche Funktionalität mit einer VIEW implementieren, die optional mit Ausdrucksindizes gekoppelt ist. Dann kann SELECT * die generierte Spalte enthalten.

"Persisted" berechnete Spalten können mit Trigger funktional identisch implementiert werden.

Materialisierte Ansichten sind ein eng verwandtes Konzept, implementiert seit Postgres 9.3 .
In früheren Versionen kann man MVs manuell verwalten.

80

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

Ich bin neu bei postgresql, aber es scheint, dass Sie berechnete Spalten erstellen können, indem Sie einen Ausdrucksindex verwenden, der mit einem view gekoppelt ist (die Ansicht ist optional, macht das Leben jedoch etwas einfacher).

Angenommen, meine Berechnung ist md5(some_string_field), dann erstelle ich den Index als: 

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

Jetzt verwenden alle Abfragen, die auf MD5(some_string_field) wirken, den Index, anstatt ihn von Grund auf neu zu berechnen. Zum Beispiel:

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

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

An dieser Stelle setzen Sie jedoch darauf, dass Benutzer der Tabelle genau wissen, wie die Spalte erstellt wird. Um das Leben zu vereinfachen, können Sie eine VIEW auf einer erweiterten Version der ursprünglichen Tabelle 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 Abfragen, die some_table_augmented verwenden, some_string_field_md5 verwenden, ohne sich Gedanken darüber zu machen, wie sie funktionieren. Sie erhalten nur eine gute Leistung. Die Ansicht kopiert keine Daten aus der Originaltabelle, daher ist sie sowohl speicher- als auch leistungsmäßig gut. Beachten Sie jedoch, dass Sie keine Aktualisierung/Einfügung in eine Ansicht durchführen können, sondern nur in die Quelltabelle. Wenn Sie jedoch wirklich wollen, können Sie Einfügungen und Aktualisierungen mit rules in die Quelltabelle umleiten dieser letzte Punkt, da ich es selbst nie probiert habe).

Edit: Wenn die Abfrage konkurrierende Indizes enthält, verwendet die Planer-Engine den Ausdruck-Index manchmal überhaupt nicht. Die Wahl scheint datenabhängig zu sein.

21
dan-man

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

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 Auslöser wird ausgelöst, bevor die Zeile aktualisiert oder eingefügt wird. Es ändert das Feld, das wir von NEW record berechnen möchten, und gibt diesen Datensatz zurück.

12
Elmer

PostgreSQL 12 unterstützt generierte Spalten:

PostgreSQL 12 Beta 1 veröffentlicht!

Generierte Spalten

In PostgreSQL 12 können generierte Spalten erstellt werden, deren Werte mit einem Ausdruck berechnet werden, wobei der Inhalt anderer Spalten verwendet wird. Diese Funktion stellt gespeicherte generierte Spalten bereit, die bei Einfügungen und Aktualisierungen berechnet und auf der Festplatte gespeichert werden. Virtuelle generierte Spalten, die nur berechnet werden, wenn eine Spalte als Teil einer Abfrage gelesen wird, werden nicht berechnet noch umgesetzt.


Generierte Spalten

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

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

db <> fiddle demo

5
Lukasz Szozda

Ich habe einen Code, der funktioniert und den Begriff berechnet verwendet. Ich bin nicht auf PostgresSQL rein, sondern auf PADB

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    ;
0
Wired604