PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Perbarui beberapa kolom dalam fungsi pemicu di plpgsql

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 dalam EXECUTE . Saya lulus NEW sebagai parameter tunggal dengan USING klausa EXECUTE .

  • 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 dengan string_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 bukannya information_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() atau format() atau dengan tipe pengidentifikasi objek. Ini termasuk variabel fungsi pemicu khusus TG_TABLE_SCHEMA dan TG_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 bukannya RETURN NULL dalam fungsi pemicu ini kecuali Anda tahu apa yang Anda lakukan. (NULL akan membatalkan INSERT 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 untuk INSERT mengharapkan kolom tampilan dan tabel berada dalam urutan yang sama . Jika Anda ingin mengizinkan urutan sewenang-wenang, tambahkan daftar definisi kolom ke INSERT perintah, seperti dengan UPDATE .

  • Versi yang diperbarui juga mencakup perubahan pada id kolom dengan menggunakan OLD tambahan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL Memilih Entri Terbaru untuk ID yang Diberikan

  2. Jumlah pesanan pengulangan / duplikat berturut-turut

  3. Kesalahan:Tidak dapat membuat TypedQuery untuk kueri dengan lebih dari satu pengembalian

  4. Bagaimana KECUALI Bekerja di PostgreSQL

  5. Nama tabel sebagai parameter fungsi PostgreSQL