Kolom dihitung / dihitung / virtual / diturunkan di PostgreSQL

113

Apakah PostgreSQL mendukung kolom yang dihitung / dihitung, seperti MS SQL Server? Saya tidak dapat menemukan apa pun di dokumen, tetapi karena fitur ini disertakan di banyak DBMS lain, saya pikir saya mungkin melewatkan sesuatu.

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

Mike Chamberlain
sumber
Menggunakan ekspresi subkueri lateral (fitur Postgres) Anda dapat dengan mudah menambahkan lebih banyak kolom ke setiap baris.
Victor

Jawaban:

139

Hingga Postgres 11 kolom yang dihasilkan tidak didukung - seperti yang didefinisikan dalam standar SQL dan diimplementasikan oleh beberapa RDBMS termasuk DB2, MySQL dan Oracle. Juga tidak "kolom dihitung" serupa dari SQL Server.

STOREDkolom yang dihasilkan diperkenalkan dengan Postgres 12 . Contoh sepele:

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

db <> biola di sini

VIRTUALkolom yang dihasilkan mungkin datang dengan salah satu dari iterasi berikutnya. (Belum di Postgres 13).

Terkait:


Sampai saat itu , Anda dapat meniru VIRTUALkolom yang dihasilkan dengan fungsi menggunakan notasi atribut ( tbl.col) yang terlihat dan berfungsi seperti kolom yang dibuat secara virtual . Itu sedikit keanehan sintaksis yang ada di Postgres karena alasan historis dan kebetulan cocok dengan kasusnya. Jawaban terkait ini memiliki contoh kode :

Ekspresi (tampak seperti kolom) tidak disertakan dalam a SELECT * FROM tbl. Anda harus selalu mencantumkannya secara eksplisit.

Dapat juga didukung dengan indeks ekspresi yang cocok - asalkan fungsinya adalah IMMUTABLE. Suka:

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

Alternatif

Alternatifnya, Anda bisa mengimplementasikan fungsionalitas serupa dengan VIEW, secara opsional digabungkan dengan indeks ekspresi. Kemudian SELECT *dapat menyertakan kolom yang dihasilkan.

STOREDKolom terhitung "Tetap" ( ) dapat diimplementasikan dengan pemicu dengan cara yang identik secara fungsional.

Pandangan terwujud adalah konsep yang terkait erat, diimplementasikan sejak Postgres 9.3 .
Dalam versi sebelumnya, seseorang dapat mengelola MV secara manual.

Erwin Brandstetter
sumber
Bergantung pada seberapa banyak data yang Anda muat sekaligus .. pemicu dapat memperlambat segalanya secara drastis. Mungkin ingin mempertimbangkan pembaruan sebagai gantinya.
sam yi
1
Solusi ini sangat tidak berguna (tanpa perubahan kode yang besar ke basis kode tanpa kasus uji) saat bermigrasi dari oracle ke postgres. Apakah ada solusi dari perspektif migrasi?
happybuddha
@happybuddha: Silakan ajukan pertanyaan Anda sebagai pertanyaan. Komentar bukanlah tempatnya. Anda selalu dapat menautkan ke pertanyaan ini untuk konteks (dan menambahkan komentar di sini untuk menarik perhatian saya dan menautkan ke pertanyaan terkait).
Erwin Brandstetter
4
Fungsionalitasnya sedang dalam pengembangan sekarang: commitfest.postgresql.org/16/1443
r90t
1
@cryanbhu: Tergantung pada detail penyiapan dan persyaratan Anda. Anda mungkin mengajukan pertanyaan baru dengan informasi yang diperlukan.
Erwin Brandstetter
32

Ya kamu bisa!! Solusinya harus mudah, aman, dan efektif ...

Saya baru mengenal postgresql, tetapi tampaknya Anda dapat membuat kolom yang dihitung dengan menggunakan indeks ekspresi , dipasangkan dengan tampilan (tampilan bersifat opsional, tetapi membuat hidup sedikit lebih mudah).

Misalkan perhitungan saya md5(some_string_field), maka saya membuat index sebagai:

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

Sekarang, kueri apa pun yang bekerja MD5(some_string_field)akan menggunakan indeks daripada menghitungnya dari awal. Sebagai contoh:

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

Anda dapat memeriksa ini dengan menjelaskan .

Namun pada titik ini Anda mengandalkan pengguna tabel yang tahu persis bagaimana membuat kolom. Untuk membuat hidup lebih mudah, Anda dapat membuat VIEWtabel asli ke versi augmented, menambahkan nilai yang dihitung sebagai kolom baru:

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

Sekarang kueri apa pun yang digunakan some_table_augmentedakan dapat digunakan some_string_field_md5tanpa mengkhawatirkan cara kerjanya .. mereka hanya mendapatkan kinerja yang baik. Tampilan tidak menyalin data apa pun dari tabel asli, jadi ini adalah memori yang baik dan juga kinerja. Namun perlu dicatat bahwa Anda tidak dapat memperbarui / menyisipkan ke dalam tampilan, hanya ke dalam tabel sumber, tetapi jika Anda benar-benar menginginkannya, saya yakin Anda dapat mengarahkan penyisipan dan pembaruan ke tabel sumber menggunakan aturan (saya bisa saja salah pada poin terakhir sebagai Saya belum pernah mencobanya sendiri).

Sunting: tampaknya jika kueri melibatkan indeks yang bersaing, mesin perencana terkadang tidak menggunakan indeks ekspresi sama sekali. Pilihannya tampaknya bergantung pada data.

dan-man
sumber
1
Bisakah Anda menjelaskan atau memberi contoh if the query involves competing indices?
dvtan
17

Salah satu cara untuk melakukannya adalah dengan pemicu!

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

Pemicu diaktifkan sebelum baris diperbarui atau disisipkan. Ini mengubah bidang yang ingin kita hitung dari NEWcatatan dan kemudian mengembalikan catatan itu.

Elmer
sumber
Kapan pemicu aktif secara akut? Saya menjalankan di atas dan melakukan ini insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;dan baru saja kembali: 1 2 dan 4 8
happybuddha
2
coba insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;nilai twokolom akan dihitung secara otomatis!
Elmer
8

PostgreSQL 12 mendukung kolom yang dihasilkan:

PostgreSQL 12 Beta 1 Dirilis!

Kolom yang Dihasilkan

PostgreSQL 12 memungkinkan pembuatan kolom yang dihasilkan yang menghitung nilainya dengan ekspresi menggunakan konten kolom lain. Fitur ini menyediakan kolom yang dihasilkan yang disimpan, yang dihitung pada penyisipan dan pembaruan dan disimpan pada disk. Kolom yang dibuat secara virtual, yang dihitung hanya ketika kolom dibaca sebagai bagian dari kueri, belum diimplementasikan.


Kolom yang Dihasilkan

Kolom yang dihasilkan adalah kolom khusus yang selalu dihitung dari kolom lain. Jadi, untuk kolom adalah tampilan untuk tabel.

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

db <> demo biola

Lukasz Szozda
sumber
1

Yah, tidak yakin apakah ini yang Anda maksud tetapi Posgres biasanya mendukung sintaks ETL "dummy". Saya membuat satu kolom kosong dalam tabel dan kemudian perlu mengisinya dengan catatan terhitung tergantung pada nilai dalam baris.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. Ini sangat bodoh, saya curiga itu bukan yang Anda cari.
  2. Jelas itu tidak dinamis, Anda menjalankannya sekali. Namun tak ada kendala untuk memicunya.
ďobo
sumber
0

Saya memiliki kode yang berfungsi dan menggunakan istilah dihitung, saya tidak menggunakan postgresSQL murni sehingga kami menjalankan di PADB

inilah cara penggunaannya

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
sumber
Apa sebenarnya PADB itu?
Gherman
Database Analitik ParAccel sudah tua tapi bagus ... en.wikipedia.org/wiki/ParAccel
Wired604
Tapi bagaimana ini berhubungan dengan pertanyaan tentang Postgres? Tentu ada banyak DB dengan dukungan kolom yang dihitung.
Gherman
ah maaf saya tidak meluangkan waktu untuk kembali ke konteks .... PADB didasarkan pada postgress!
Wired604
-6

Solusi ringan dengan kendala Periksa:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);
cinereo
sumber
6
Bagaimana ini terkait dengan konsep kolom terhitung? Maukah Anda menjelaskan?
Erwin Brandstetter
4
Setuju, itu tidak terkait langsung. Tetapi ini adalah pengganti untuk kasus sederhana ketika Anda hanya perlu melakukan sesuatu seperti itu field as 1 persisted.
cinereo
2
Deskripsi memang akan menyenangkan. Saya pikir jawaban ini adalah bahwa jika perhitungan dapat dilakukan dengan klausa default maka Anda dapat menggunakan default dan kendala cek untuk mencegah siapa pun mengubah nilainya.
Ross Bradbury
@ Ross Bradbury: Setuju, tapi itu hanya berfungsi untuk penyisipan. Ini tidak akan berfungsi jika kolom dependen diperbarui.
Stefan Steiger