Kolumny obliczane / obliczane / wirtualne / pochodne w PostgreSQL

113

Czy PostgreSQL obsługuje kolumny obliczeniowe / obliczeniowe, takie jak MS SQL Server? Nie mogę znaleźć niczego w dokumentacji, ale ponieważ ta funkcja jest zawarta w wielu innych systemach DBMS, pomyślałem, że mogę czegoś przegapić.

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

Mike Chamberlain
źródło
Używając bocznego wyrażenia podzapytania (funkcja Postgres) możesz łatwo dodać więcej kolumn do każdego wiersza.
Victor,

Odpowiedzi:

139

Kolumny generowane do Postgres 11 nie są obsługiwane - zgodnie ze standardem SQL i implementowanymi przez niektóre RDBMS, w tym DB2, MySQL i Oracle. Ani podobne „kolumny obliczeniowe” SQL Server.

STOREDwygenerowane kolumny są wprowadzane w Postgres 12 . Trywialny przykład:

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

db <> skrzypce tutaj

VIRTUALwygenerowane kolumny mogą zawierać jedną z następnych iteracji. (Jeszcze nie w Postgres 13).

Związane z:


Do tego czasu można emulować VIRTUALkolumny generowane za pomocą funkcji używającej notacji atrybutu ( tbl.col), która wygląda i działa podobnie jak wirtualna kolumna generowana . To trochę dziwaczna składnia, która istnieje w Postgres z powodów historycznych i pasuje do przypadku. Ta powiązana odpowiedź zawiera przykłady kodu :

Wyrażenie (wyglądające jak kolumna) nie jest jednak zawarte w a SELECT * FROM tbl. Zawsze musisz to wyraźnie wymienić.

Może być również obsługiwany za pomocą pasującego indeksu wyrażenia - pod warunkiem, że funkcja jest IMMUTABLE. Lubić:

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

Alternatywy

Alternatywnie możesz zaimplementować podobną funkcjonalność za pomocą VIEW, opcjonalnie w połączeniu z indeksami wyrażeń. Następnie SELECT *można dołączyć wygenerowaną kolumnę.

STOREDKolumny obliczane „Persisted” ( ) można zaimplementować z wyzwalaczami w funkcjonalnie identyczny sposób.

Widoki zmaterializowane to ściśle związana koncepcja, wprowadzona od Postgres 9.3 .
We wcześniejszych wersjach można ręcznie zarządzać MV.

Erwin Brandstetter
źródło
W zależności od tego, ile danych ładujesz naraz, wyzwalacz może drastycznie spowolnić działanie. Zamiast tego warto rozważyć aktualizacje.
sam yi
1
Te rozwiązania są praktycznie bezużyteczne (bez ogromnych zmian w kodzie w bazie kodu bez przypadków testowych) podczas migracji z Oracle do Postgres. Czy są jakieś rozwiązania z perspektywy migracji?
happybuddha
@happybuddha: Zadaj pytanie jako pytanie. Komentarze nie są miejscem. Zawsze możesz podać link do tego pytania, aby uzyskać kontekst (i dodać tutaj komentarz, aby zwrócić moją uwagę i łącze do powiązanego pytania).
Erwin Brandstetter
4
Funkcjonalność jest obecnie w fazie rozwoju: commitfest.postgresql.org/16/1443
r90t
1
@cryanbhu: Zależy od szczegółów konfiguracji i wymagań. Możesz zadać nowe pytanie z niezbędnymi informacjami.
Erwin Brandstetter
32

Tak, możesz!! Rozwiązanie powinno być łatwe, bezpieczne i wydajne ...

Jestem nowy w postgresql, ale wygląda na to, że możesz tworzyć kolumny obliczone za pomocą indeksu wyrażeń w połączeniu z widokiem (widok jest opcjonalny, ale sprawia, że ​​życie jest trochę łatwiejsze).

Załóżmy, że moje obliczenia to md5(some_string_field), a następnie tworzę indeks jako:

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

Teraz wszelkie zapytania, na podstawie których działają, MD5(some_string_field)będą używać indeksu, zamiast obliczać go od zera. Na przykład:

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

Możesz to sprawdzić, wyjaśniając .

Jednak w tym momencie polegasz na tym, że użytkownicy tabeli wiedzą dokładnie, jak zbudować kolumnę. Aby ułatwić sobie życie, możesz utworzyć VIEWrozszerzoną wersję oryginalnej tabeli, dodając obliczoną wartość jako nową kolumnę:

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

Teraz wszystkie zapytania, które używają, some_table_augmentedbędą mogły być używane some_string_field_md5bez martwienia się o to, jak to działa… Po prostu uzyskują dobrą wydajność. Widok nie kopiuje żadnych danych z oryginalnej tabeli, więc jest dobry zarówno pod względem pamięci, jak i wydajności. Pamiętaj jednak, że nie możesz aktualizować / wstawiać do widoku, tylko do tabeli źródłowej, ale jeśli naprawdę chcesz, uważam, że możesz przekierować wstawki i aktualizacje do tabeli źródłowej za pomocą reguł (mogę się mylić w tym ostatnim punkcie, ponieważ Sam nigdy tego nie próbowałem).

Edycja: wydaje się, że jeśli zapytanie dotyczy konkurencyjnych indeksów, silnik planowania może czasami w ogóle nie używać indeksu wyrażenia. Wybór wydaje się zależeć od danych.

dan-man
źródło
1
Czy mógłbyś wyjaśnić lub podać przykład if the query involves competing indices?
dvtan
17

Jednym ze sposobów jest użycie spustu!

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();

Wyzwalacz jest uruchamiany przed aktualizacją lub wstawieniem wiersza. Zmienia pole, które chcemy obliczyć na NEWrekord, a następnie zwraca ten rekord.

Elmer
źródło
Kiedy aktywuje się spust? Uruchomiłem powyższe i zrobiłem to insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;i właśnie wróciło: 1 2 i 4 8
happybuddha
2
spróbuj insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;wartość twokolumny zostanie obliczona automagicznie!
Elmer
8

PostgreSQL 12 obsługuje generowane kolumny:

Wydano PostgreSQL 12 Beta 1!

Wygenerowane kolumny

PostgreSQL 12 umożliwia tworzenie generowanych kolumn, które obliczają ich wartości za pomocą wyrażenia wykorzystującego zawartość innych kolumn. Ta funkcja zapewnia przechowywane wygenerowane kolumny, które są obliczane na wstawkach i aktualizacjach oraz zapisywane na dysku. Wirtualne kolumny generowane, które są obliczane tylko wtedy, gdy kolumna jest odczytywana jako część zapytania, nie są jeszcze zaimplementowane.


Wygenerowane kolumny

Kolumna generowana to specjalna kolumna, która jest zawsze obliczana na podstawie innych kolumn. Zatem dla kolumn jest tym, czym widok dla tabel.

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

db <> fiddle demo

Łukasz Szozda
źródło
Artykuł na blogu: 2ndquadrant.com/en/blog/generated-columns-in-postgresql-12
Christophe Roussy,
1

Cóż, nie jestem pewien, czy to masz na myśli, ale Posgres normalnie obsługuje "fikcyjną" składnię ETL. Utworzyłem jedną pustą kolumnę w tabeli, a następnie musiałem wypełnić ją obliczonymi rekordami w zależności od wartości w wierszu.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. Jest tak głupi, że podejrzewam, że nie jest tym, czego szukasz.
  2. Oczywiście nie jest dynamiczny, uruchamiasz go raz. Ale nie ma przeszkód, aby go uruchomić.
ďobo
źródło
0

Mam kod, który działa i używam obliczonego terminu, nie korzystam z czystego PostgresSQL, chociaż uruchamiamy na PADB

oto jak jest używany

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    ;
Przewodowy604
źródło
Czym dokładnie jest PADB?
Gherman
ParAccel Analytic Database jest stara, ale ładna ... pl.wikipedia.org/wiki/ParAccel
Wired604
Ale jak to się ma do pytania o Postgres? Z pewnością istnieje wiele baz danych obsługujących kolumny obliczeniowe.
Gherman
ah przepraszam, nie poświęciłem czasu na powrót do kontekstu ... PADB jest oparty na postgress!
Wired604
-6

Lekkie rozwiązanie z ograniczeniem Sprawdź:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
cinereo
źródło
6
Jak to się ma do pojęcia kolumny obliczeniowej? Czy mógłbyś to wyjaśnić?
Erwin Brandstetter
4
Zgoda, to nie jest bezpośrednio związane. Ale jest substytutem prostego przypadku, w którym wystarczy zrobić coś podobnego field as 1 persisted.
cinereo
2
Opis rzeczywiście byłby miły. Myślę, że ta odpowiedź jest taka, że ​​jeśli obliczenia można wykonać z klauzulą ​​domyślną, możesz użyć ograniczenia domyślnego i sprawdzającego, aby uniemożliwić komukolwiek zmianę wartości.
Ross Bradbury
@ Ross Bradbury: Zgoda, ale to działa tylko w przypadku wstawiania. Nie działałoby, gdyby zaktualizowana kolumna zależna.
Stefan Steiger