Colonne calcolate / calcolate / virtuali / derivate in PostgreSQL


113

PostgreSQL supporta colonne calcolate / calcolate, come MS SQL Server? Non riesco a trovare nulla nei documenti, ma poiché questa funzione è inclusa in molti altri DBMS, ho pensato che mi mancasse qualcosa.

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


Utilizzando l'espressione di sottoquery laterale (funzione Postgres) puoi aggiungere facilmente più colonne a ciascuna riga.
Victor

Risposte:


139

Le colonne generate fino a Postgres 11 non sono supportate, come definito nello standard SQL e implementato da alcuni RDBMS inclusi DB2, MySQL e Oracle. Né le simili "colonne calcolate" di SQL Server.

STOREDle colonne generate vengono introdotte con Postgres 12 . Esempio banale:

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

db <> fiddle qui

VIRTUALcolonne generate possono venire con una delle successive iterazioni. (Non in Postgres 13, ancora).

Relazionato:


Fino ad allora , puoi emulare le VIRTUALcolonne generate con una funzione utilizzando l' attributo notation ( tbl.col) che assomiglia e funziona in modo molto simile a una colonna generata virtuale . Questa è un po 'una stranezza sintattica che esiste in Postgres per ragioni storiche e che sembra adattarsi al caso. Questa risposta correlata ha esempi di codice :

Tuttavia, l'espressione (che sembra una colonna) non è inclusa in a SELECT * FROM tbl. Devi sempre elencarlo esplicitamente.

Può anche essere supportato con un indice di espressione corrispondente , a condizione che la funzione lo sia IMMUTABLE. Piace:

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

alternative

In alternativa, è possibile implementare funzionalità simili con un VIEW, facoltativamente accoppiato con indici di espressione. Quindi SELECT *può includere la colonna generata.

Le STOREDcolonne calcolate "Persisted" ( ) possono essere implementate con i trigger in modo funzionalmente identico.

Le viste materializzate sono un concetto strettamente correlato, implementato da Postgres 9.3 .
Nelle versioni precedenti è possibile gestire manualmente le MV.


A seconda della quantità di dati che stai caricando contemporaneamente, il trigger può rallentare drasticamente le cose. Potrebbe invece prendere in considerazione gli aggiornamenti.
sam yi

1
Queste soluzioni sono praticamente inutili (senza enormi modifiche al codice in una base di codice senza casi di test) durante la migrazione da Oracle a Postgres. Esistono soluzioni dal punto di vista della migrazione?
happybuddha

@happybuddha: per favore fai la tua domanda come domanda. I commenti non sono il posto giusto. Puoi sempre collegarti a questa domanda per il contesto (e aggiungere un commento qui per attirare la mia attenzione e collegare alla domanda correlata).
Erwin Brandstetter

4
La funzionalità è in fase di sviluppo in questo momento: commitfest.postgresql.org/16/1443
r90t

1
@cryanbhu: dipende dai dettagli della configurazione e dai requisiti. Potresti porre una nuova domanda con le informazioni necessarie.
Erwin Brandstetter

32

Si, puoi!! La soluzione dovrebbe essere facile, sicura e performante ...

Sono nuovo di postgresql, ma sembra che tu possa creare colonne calcolate utilizzando un indice di espressione , associato a una vista (la vista è opzionale, ma rende la vita un po 'più facile).

Supponiamo che il mio calcolo sia md5(some_string_field), quindi creo l'indice come:

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

Ora, qualsiasi query su cui agisce MD5(some_string_field)utilizzerà l'indice anziché calcolarlo da zero. Per esempio:

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

Puoi verificarlo con spiegare .

Tuttavia a questo punto ti affidi agli utenti della tabella che sanno esattamente come costruire la colonna. Per semplificarti la vita, puoi creare una VIEWversione aumentata della tabella originale, aggiungendo il valore calcolato come nuova colonna:

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

Ora tutte le query che utilizzano some_table_augmentedsaranno in grado di essere utilizzate some_string_field_md5senza preoccuparsi di come funziona .. ottengono solo buone prestazioni. La vista non copia alcun dato dalla tabella originale, quindi è buona sia dal punto di vista della memoria che da quello delle prestazioni. Nota tuttavia che non puoi aggiornare / inserire in una vista, solo nella tabella di origine, ma se lo desideri davvero, credo che tu possa reindirizzare gli inserimenti e gli aggiornamenti alla tabella di origine utilizzando le regole (potrei sbagliarmi su quest'ultimo punto come Non l'ho mai provato io stesso).

Modifica: sembra che se la query coinvolge indici concorrenti, il motore di pianificazione a volte potrebbe non utilizzare affatto l'indice di espressione. La scelta sembra dipendere dai dati.


1
Potresti spiegare o fornire un esempio di if the query involves competing indices?
dvtan

17

Un modo per farlo è con un trigger!

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

Il trigger viene attivato prima che la riga venga aggiornata o inserita. Cambia il campo che vogliamo calcolare del NEWrecord e quindi restituisce quel record.


Quando si attiva il grilletto? Ho eseguito quanto sopra e l'ho fatto insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;ed è appena tornato: 1 2 e 4 8
happybuddha

2
prova insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;il valore della twocolonna verrà calcolato automagicamente!
Elmer

8

PostgreSQL 12 supporta le colonne generate:

PostgreSQL 12 Beta 1 rilasciato!

Colonne generate

PostgreSQL 12 consente la creazione di colonne generate che calcolano i propri valori con un'espressione utilizzando il contenuto di altre colonne. Questa funzione fornisce colonne generate archiviate, che vengono calcolate su inserimenti e aggiornamenti e vengono salvate su disco. Le colonne generate virtuali, che vengono calcolate solo quando una colonna viene letta come parte di una query, non sono ancora implementate.


Colonne generate

Una colonna generata è una colonna speciale che viene sempre calcolata da altre colonne. Quindi, è per le colonne ciò che una vista è per le tabelle.

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

db <> fiddle demo



1

Beh, non sono sicuro che questo sia ciò che intendi, ma Posgres normalmente supporta la sintassi ETL "fittizia". Ho creato una colonna vuota nella tabella e quindi ho dovuto riempirla con record calcolati in base ai valori nella riga.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. È così fittizio che sospetto che non sia quello che stai cercando.
  2. Ovviamente non è dinamico, lo esegui una volta. Ma nessun ostacolo per farlo scattare.

0

Ho un codice che funziona e utilizzo il termine calcolato, non sono su postgresSQL puro anche se giriamo su PADB

ecco come viene utilizzato

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    ;

Cos'è esattamente PADB?
Gherman

ParAccel Analytic Database è vecchio ma carino ... en.wikipedia.org/wiki/ParAccel
Wired604

Ma come si collega a una domanda su Postgres? Sicuramente ci sono molti DB con supporto di colonne calcolate.
Gherman

ah scusa non ho avuto il tempo di tornare nel contesto .... PADB è basato sul postgress!
Wired604

-6

Una soluzione leggera con vincolo Check:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
Che relazione c'è con il concetto di colonna calcolata? Ti andrebbe di spiegare?
Erwin Brandstetter

4
D'accordo, non è direttamente correlato. Ma è una sostituzione per un semplice caso in cui devi solo fare qualcosa di simile field as 1 persisted.
cinereo

2
Una descrizione sarebbe stata davvero carina. Penso che questa risposta sia che se il calcolo può essere eseguito con la clausola predefinita, è possibile utilizzare un vincolo predefinito e un controllo per impedire a chiunque di modificare il valore.
Ross Bradbury

@ Ross Bradbury: d'accordo, ma funziona solo per l'inserimento. Non funzionerebbe se una colonna dipendente venisse aggiornata.
Stefan Steiger
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.