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

Loop tak berujung dalam fungsi pemicu

ELSE cabang dapat disederhanakan secara radikal. Tetapi beberapa hal lagi tidak efisien / tidak akurat / berbahaya:

CREATE OR REPLACE FUNCTION sample_trigger_func()
  RETURNS TRIGGER AS
$func$
BEGIN
   IF TG_OP = 'DELETE' THEN
      RAISE INFO 'OLD: %', OLD.name;

      EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
      USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
                         , ARRAY[left(TG_OP, 1), now()::text]);
      RETURN OLD;
   ELSE  -- insert, update
      NEW.mod_op       := left(TG_OP, 1);
      NEW.mod_datetime := now();

      RETURN NEW;
   END IF;
END
$func$  LANGUAGE plpgsql;
  • Dalam ELSE cabang cukup tetapkan ke NEW secara langsung. Tidak perlu SQL yang lebih dinamis - yang akan memicu pemicu yang sama lagi menyebabkan loop tanpa akhir. Itulah kesalahan utama.

  • RETURN NEW; di luar IF konstruksi akan merusak fungsi pemicu Anda untuk DELETE , sejak NEW tidak ditetapkan untuk DELETE.

  • Fitur utama adalah penggunaan hstore dan operator hstore #= untuk secara dinamis mengubah dua bidang yang dipilih dari jenis baris terkenal - itu tidak diketahui pada saat penulisan kode. Dengan cara ini Anda tidak merusak OLD asli nilai, yang mungkin memiliki efek samping yang mengejutkan jika Anda memiliki lebih banyak pemicu dalam rangkaian peristiwa.

    OLD #= hstore('{mod_op, mod_datetime}'::text[]
                 , ARRAY[left(TG_OP, 1), now()::text]);
    

    Modul tambahan hstore harus dipasang. Detail:

    Menggunakan hstore(text[], text[]) varian di sini untuk membuat hstore nilai dengan beberapa bidang dengan cepat.

  • Operator penugasan di plpgsql adalah := :

  • Perhatikan bahwa saya menggunakan nama kolom mod_datetime bukannya mod_date misleading yang menyesatkan , karena kolom tersebut jelas merupakan timestamp dan bukan date .

Saya menambahkan beberapa peningkatan lain saat melakukannya. Dan pemicunya sendiri akan terlihat seperti ini:

CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();

SQL Fiddle.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tetapkan secara dinamis jenis baris yang dikembalikan berdasarkan tabel yang diberikan di plpgsql?

  2. Bagaimana cara menghapus urutan yang tidak digunakan?

  3. Rails:Menyebarkan ke Heroku, Banyak Masalah

  4. Pemicu sisipan Postgresql untuk digabungkan

  5. Daftar Kedekatan ke grafik JSON dengan Postgres