PostgreSQL: Wygenerowane kolumny

16

Czy PostgreSQL obsługuje generowane kolumny ? Znane również jako wirtualne kolumny . Ja nie mówić o IDENTITYkolumnach .

Nie mogę znaleźć żadnych informacji na temat tej niezwykłej funkcji, ale wiem, że jest ona dostępna na SQL Server oraz w najnowszych wersjach MariaDB i MySQL.

Ta funkcja jest wspomniana w standardzie SQL: 2003 , a na forach PostgreSQL była dyskusja około 2006 roku, ale nie mogę znaleźć nic istotnego w tej sprawie.

Trwa dyskusja na temat SO, ale jest już dość stara, więc może być nieaktualna.

Manngo
źródło
2
Ta pokrewna odpowiedź z SO na 2012 rok może być pomocna: stackoverflow.com/questions/11165450/... Nadal obowiązuje.
Erwin Brandstetter,
@ErwinBrandstetter Przepraszamy, brakowało mi tego komentarza. To przydatna sztuczka. Dzięki.
Manngo,

Odpowiedzi:

17

Nie jestem pewien, czy tego właśnie chcesz, ale notacja atrybutu row.full_namei notacja funkcji full_name(row)są równoważne w postgresql.

Oznacza to, że weźmiesz stolik

CREATE TABLE people (
  first_name text,
  last_name text
);

i funkcja:

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

i nazwij to tak:

select full_name from people

Czy tego potrzebujesz?

Aby przyspieszyć, możesz utworzyć indeks wyrażeń:

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

Lub przechowuj wszystko w zmaterializowanym widoku.

Przykład wzięty stąd: http://bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/

Fabian Zeindl
źródło
2
To jest poprawna odpowiedź. Zobacz na przykład, jak Postgrest określa to zachowanie jako „kolumny obliczane”.
fiatjaf
Wydaje mi się, że literówka - należy wybrać select people.full_name from peoplelub select full_name(people) from people?
Barguast,
Nie, tak to działa. Prefiks w „select people.full_name from people” można pominąć, tak jak w zwykłym SQL.
Fabian Zeindl,
Tęskniłem za odpowiedzią, nadeszła niejako długo po tym, jak się poddałem. Dzieki za sugestie.
Manngo,
1
Czy mógłbyś wtedy zmienić przyjętą odpowiedź?
Fabian Zeindl
6

Nie, obecnie nie jest to obsługiwane (od Postgres 9.6).

Jedynym obejściem jest użycie wyzwalacza lub widoku, jeśli jest to proste obliczenie, którego nie trzeba indeksować.

koń bez imienia
źródło
Szczury Przypuszczam, że gdybym potrzebowała przedstawienia, mogłabym wybrać widok zmaterializowany. Dodałem prośbę o tę funkcję, ponieważ jest ona już dostępna w konkursie.
Manngo,
1
Nie ma potrzeby MVIEW. Kolumna z wyzwalaczem pozwoli również na indeksowanie zawartości kolumny
a_horse_w_no_name
Mam filozoficzny problem z przechowywaniem dodatkowych prawdziwych kolumn, które są w zasadzie powtórzeniem innych danych. To znormalizuje stół.
Manngo,
5
Cóż, kolumna obliczeniowa to dokładnie to: przechowywanie zdenormalizowanych danych. Sposób generowania wartości kolumny obliczanej nie ma znaczenia. Nie widzę różnicy pojęciowej między „prawdziwą” kolumną obliczeniową a kolumną generowaną za pomocą wyzwalacza
a_horse_w__nazwie
Innym obejściem (w niektórych przypadkach) jest indeksowanie wyrażenia.
ypercubeᵀᴹ
5

Tak: GENERATED ALWAYS AS … STORED

Postgres 12 dodaje funkcjonalność dla generowanych kolumn, jak wspomniano w standardzie SQL: 2003 .

Wartość jest generowana w momencie INSERTlub UPDATE, a następnie przechowywana w wierszu, jak każda inna wartość.

Wygenerowany musi być oparty na kolumnie podstawowej tej samej tabeli lub na niezmiennej funkcji .

Składnia jest prosta, klauzula dotycząca CREATE TABLE:

GENERATED ALWAYS AS ( generation_expr ) STORED 

Przykład:

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

Cechy:

  • Może być indeksowany.
  • Część standardu SQL.

Ostrzeżenia:

  • Na podstawie kolumn tej samej tabeli (tabele niepowiązane)
  • Niedozwolone do partycjonowania (nie może być częścią klucza partycji)
  • Dane zawsze zapisywane do wiersza, zajmując miejsce w pamięci
    • Przyszła funkcja może oferować VIRTUAL dla wartości obliczanych w locie bez przechowywania
  • Głębokie pojedynczej generacji (użyj kolumny bazowej, a nie innej kolumny generowanej)
  • Nie ma opcji WYGENEROWANE WG DOMYŚLNYCH (nie można przesłonić wartości)
  • Nie można uzyskać dostępu do gen-col w wyzwalaczu PRZED (wartość jeszcze nie ustalona)
  • Funkcje muszą być niezmienne

Widzieć:

Basil Bourque
źródło
Dzięki za te informacje. Widzę, że wersja 12 nie została jeszcze w pełni wydana, ale nie mogę się doczekać. Zauważam, że PostgreSQL używa bardziej standardowej składni, ale poza tym jest taki sam jak MSSQL. Znalazłem specyfikacje SQL2003 tutaj: sigmodrecord.org/publications/sigmodRecord/0403/… . Zawsze mówiłem, że SQL jest bardzo wolno zmieniającym się standardem, a implementacje DBMS są nawet powolne.
Manngo,
0

W zależności od przypadku użycia można osiągnąć takie zachowanie, deklarując nową kolumnę i wypełniając ją wyzwalaczem podczas wstawiania / aktualizacji.

Użyłbym powyższych odpowiedzi, jeśli to możliwe, aby uniknąć powielania danych, które można uzyskać z tego, co już masz, ale robi to sztuczkę i może być użyteczny w intensywnych obliczeniowo polach pochodnych, które chcesz obliczyć raz i zapisać.

Rozważyłem to podejście do rozwiązania problemu, w którym czasami miałem tylko 15 cyfr 18-cyfrowego klucza (ostatnie 3 cyfry to tylko suma kontrolna), ale chciałem móc wymusić relację klucza obcego.

Dokumenty PG dotyczące wyzwalaczy: https://www.postgresql.org/docs/9.6/sql-createtrigger.html

Przykład W3: https://www.w3resource.com/PostgreSQL/postgresql-triggers.php

Allen Phelps
źródło