Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Apa cara termudah untuk membuat kolom READONLY di Oracle?

Jika ada tabel anak yang diisi dengan data yang mereferensikan INITIATIVEID kolom, Oracle akan secara otomatis mempersulit untuk mengubah nilai kunci utama dengan mencegah Anda membuat baris yatim piatu dengan mengubah kunci utama induk. Jadi, misalnya, jika ada tabel anak yang memiliki batasan kunci asing ke TPM_INITIATIVES dan ada baris di tabel anak ini dengan INITIATIVEID dari 17, Anda tidak akan dapat mengubah INITIATIVEID dari baris di TPM_INITIAITVES tabel yang nilainya saat ini adalah 17. Jika tidak ada baris dalam tabel anak mana pun yang merujuk ke baris tertentu di TPM_INITIATIVES tabel, Anda bisa mengubah nilainya tetapi, mungkin, jika tidak ada hubungan, mengubah nilai kunci utama tidak penting karena menurut definisi tidak dapat menyebabkan masalah integritas data. Tentu saja, Anda dapat memiliki kode yang menyisipkan baris baru ke dalam TPM_INITIATIVES dengan INITIATIVEID baru , ubah semua baris di tabel anak yang merujuk ke baris lama untuk merujuk ke baris baru, lalu ubah baris lama. Tapi ini tidak akan terjebak oleh salah satu solusi yang diusulkan.

Jika aplikasi Anda telah mendefinisikan tabel anak tetapi tidak mendeklarasikan batasan kunci asing yang sesuai, itu akan menjadi cara terbaik untuk menyelesaikan masalah.

Karena itu, solusi Arnon untuk membuat tampilan harus berfungsi. Anda akan mengganti nama tabel, membuat tampilan dengan nama yang sama dengan tabel yang ada, dan (berpotensi) menentukan pemicu BUKAN pada tampilan yang tidak akan pernah memperbarui INITIATIVEID kolom. Itu seharusnya tidak memerlukan perubahan pada bagian lain dari aplikasi.

Anda juga dapat menentukan pemicu di tabel

CREATE TRIGGER trigger_name 
  BEFORE UPDATE ON TPM_INITIATIVES  
  FOR EACH ROW
DECLARE
BEGIN
  IF( :new.initiativeID != :old.initiativeID )
  THEN
    RAISE_APPLICATION_ERROR( -20001, 'Sorry Charlie.  You can''t update the initiativeID column' );
  END IF;
END;

Seseorang dapat, tentu saja, menonaktifkan pemicu dan mengeluarkan pembaruan. Tapi saya berasumsi Anda tidak mencoba menghentikan penyerang, hanya sepotong kode yang bermasalah.

Namun, berdasarkan deskripsi gejala apa yang Anda lihat, akan lebih masuk akal untuk mencatat riwayat perubahan pada kolom dalam tabel ini sehingga Anda dapat benar-benar menentukan apa yang sedang terjadi daripada menebak dan mencoba memasukkan lubang satu -dengan satu. Jadi, misalnya, Anda bisa melakukan sesuatu seperti ini

CREATE TABLE TPM_INITIATIVES_HIST (
   INITIATIVEID    NUMBER NOT NULL,
   NAME            VARCHAR2(100) NOT NULL,
   ACTIVE          CHAR(1) NULL,
   SORTORDER       NUMBER NULL,
   SHORTNAME       VARCHAR2(100) NULL,
   PROJECTTYPEID   NUMBER NOT NULL,
   OPERATIONTYPE   VARCHAR2(1) NOT NULL,
   CHANGEUSERNAME  VARCHAR2(30),
   CHANGEDATE      DATE,
   COMMENT         VARCHAR2(4000)
);

CREATE TRIGGER trigger_name 
  BEFORE INSERT or UPDATE or DELETE ON TPM_INITIATIVES  
  FOR EACH ROW
DECLARE
  l_comment VARCHAR2(4000);
BEGIN
  IF( inserting )
  THEN
    INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID, 
                                      OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
      VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID, 
              'I', USER, SYSDATE );
  ELSIF( inserting )
  THEN
    IF( :new.initiativeID != :old.initiativeID )
    THEN
      l_comment := 'Initiative ID changed from ' || :old.initiativeID || ' to ' || :new.initiativeID;
    END IF;
    INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID, 
                                      OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE, COMMENT )
      VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID, 
              'U', USER, SYSDATE, l_comment );
  ELSIF( deleting )
  THEN
    INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID, 
                                      OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
      VALUES( :old.initiativeID, :old.name, :old.active, :old.sortOrder, :old.shortName, :old.projectTypeID, 
              'D', USER, SYSDATE );
  END IF;
END;

Kemudian Anda dapat menanyakan TPM_INITIATIVES_HIST untuk melihat semua perubahan yang telah dibuat pada baris tertentu dari waktu ke waktu. Jadi, Anda dapat melihat apakah nilai kunci utama berubah atau seseorang hanya mengubah bidang non-kunci. Idealnya, Anda mungkin memiliki kolom tambahan yang dapat Anda tambahkan ke tabel riwayat untuk membantu melacak perubahan (mis. mungkin ada sesuatu dari V$SESSION yang mungkin berguna).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mengapa EXECUTE IMMEDIATE diperlukan di sini?

  2. Cara Memperbarui kolom BLOB, kesalahan ORA-00932, saat Sisipkan berfungsi

  3. Apakah ada cara untuk memilih beberapa baris dengan menggunakan parameter?

  4. OLEDB tercepat dibaca dari ORACLE

  5. Konversikan keluaran kueri Oracle ke json (Oracle / NodeJS)