Sementara jawaban @ Gary secara teknis benar, ia gagal menyebutkan bahwa PostgreSQL benar dukung formulir ini:
UPDATE tbl
SET (col1, col2, ...) = (expression1, expression2, ..)
Baca manual di UPDATE
sekali lagi.
Masih sulit untuk menyelesaikannya dengan SQL dinamis. Karena Anda tidak menentukan, saya mengasumsikan kasus sederhana di mana tampilan terdiri dari kolom yang sama dengan tabel yang mendasarinya.
CREATE VIEW tbl_view AS SELECT * FROM tbl;
Masalah
-
Catatan khusus
NEW
tidak terlihat di dalamEXECUTE
. Saya lulusNEW
sebagai parameter tunggal denganUSING
klausaEXECUTE
. -
Seperti yang telah dibahas,
UPDATE
dengan formulir daftar membutuhkan nilai individu . Saya menggunakan subpilihan untuk membagi catatan menjadi kolom individual:UPDATE ... FROM (SELECT ($1).*) x
(Kurung di sekitar
$1
tidak opsional.) Ini memungkinkan saya untuk menggunakan dua daftar kolom yang dibuat denganstring_agg()
dari tabel katalog:satu dengan dan satu tanpa kualifikasi tabel. -
Tidak mungkin menetapkan nilai baris secara keseluruhan ke masing-masing kolom. Panduan:
Menurut standar, nilai sumber untuk sub-daftar yang dikurung dari nama kolom target dapat berupa ekspresi bernilai baris apa pun yang menghasilkan jumlah kolom yang benar. PostgreSQL hanya mengizinkan nilai sumber menjadi konstruktor baris atau sub-
SELECT
. -
INSERT
diimplementasikan lebih sederhana. Dengan asumsi struktur tampilan dan tabel identik, saya menghilangkan daftar definisi kolom. (Dapat ditingkatkan, lihat di bawah.)
Solusi
Saya membuat sejumlah pembaruan pada pendekatan Anda untuk membuatnya bersinar.
Fungsi pemicu untuk UPDATE
:
CREATE OR REPLACE FUNCTION f_trg_up()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
cols text;
vals text;
BEGIN
SELECT INTO cols, vals
string_agg(quote_ident(attname), ', ')
,string_agg('x.' || quote_ident(attname), ', ')
FROM pg_attribute
WHERE attrelid = tbl::regclass
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
EXECUTE format('
UPDATE %s t
SET (%s) = (%s)
FROM (SELECT ($1).*) x
WHERE t.id = ($2).id'
, tbl, cols, vals) -- assuming unique "id" in every table
USING NEW, OLD;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Fungsi pemicu untuk INSERT
:
CREATE OR REPLACE FUNCTION f_trg_ins()
RETURNS TRIGGER AS
$func$
DECLARE
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(substring(TG_TABLE_NAME from '(.+)_view$'));
BEGIN
EXECUTE 'INSERT INTO ' || tbl || ' SELECT ($1).*'
USING NEW;
RETURN NEW; -- don't return NULL unless you know what you're doing
END
$func$ LANGUAGE plpgsql;
Pemicu:
CREATE TRIGGER trg_instead_up
INSTEAD OF UPDATE ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_up();
CREATE TRIGGER trg_instead_ins
INSTEAD OF INSERT ON a_view
FOR EACH ROW EXECUTE PROCEDURE f_trg_ins();
SQL Fiddle mendemonstrasikan INSERT
dan UPDATE
.
Poin utama
-
Sertakan nama skema untuk membuat referensi tabel tidak ambigu. Mungkin ada beberapa contoh nama tabel yang sama dalam database yang sama dalam beberapa skema!
-
Kueri
pg_attribute
bukannyainformation_schema.columns
. Itu kurang portabel, tapi banyak lebih cepat dan memungkinkan saya untuk menggunakan table-OID.- Cara memeriksa apakah ada tabel dalam skema tertentu
-
Nama tabel TIDAK aman terhadap SQLi ketika ditangani sebagai string seperti dalam membangun kueri untuk SQL dinamis. Melarikan diri dengan
quote_ident()
atauformat()
atau dengan tipe pengidentifikasi objek. Ini termasuk variabel fungsi pemicu khususTG_TABLE_SCHEMA
danTG_TABLE_NAME
! -
Transmisikan ke tipe pengenal objek
regclass
untuk menegaskan bahwa nama tabel valid dan mendapatkan OID untuk pencarian katalog. -
Secara opsional gunakan
format()
untuk membangun string kueri dinamis dengan aman. -
Tidak perlu SQL dinamis untuk kueri pertama di tabel katalog. Lebih cepat, lebih sederhana.
-
Gunakan
RETURN NEW
bukannyaRETURN NULL
dalam fungsi pemicu ini kecuali Anda tahu apa yang Anda lakukan. (NULL
akan membatalkanINSERT
untuk baris saat ini.) -
Versi sederhana ini mengasumsikan bahwa setiap tabel (dan tampilan) memiliki kolom unik bernama
id
. Versi yang lebih canggih mungkin menggunakan kunci utama secara dinamis. -
Fungsi untuk
UPDATE
memungkinkan kolom tampilan dan tabel berada dalam urutan apa pun , asalkan himpunannya sama. Fungsi untukINSERT
mengharapkan kolom tampilan dan tabel berada dalam urutan yang sama . Jika Anda ingin mengizinkan urutan sewenang-wenang, tambahkan daftar definisi kolom keINSERT
perintah, seperti denganUPDATE
. -
Versi yang diperbarui juga mencakup perubahan pada
id
kolom dengan menggunakanOLD
tambahan.