Oracle
 sql >> база данни >  >> RDS >> Oracle

Кой е най-лесният начин да направите колона САМО ЗА ЧЕТЕНЕ в Oracle?

Ако има дъщерни таблици, попълнени с данни, които препращат към INITIATIVEID колона, Oracle трябва автоматично да затрудни промяната на стойността на първичния ключ, като ви попречи да създавате осиротели редове чрез промяна на първичния ключ на родителя. Така например, ако има дъщерна таблица, която има ограничение за външен ключ към TPM_INITIATIVES и има ред в тази дъщерна таблица с INITIATIVEID от 17, няма да можете да промените INITIATIVEID от реда в TPM_INITIAITVES таблица, чиято текуща стойност е 17. Ако няма ред в нито една дъщерна таблица, който препраща към конкретния ред в TPM_INITIATIVES можете да промените стойността, но вероятно, ако няма връзки, промяната на стойността на първичния ключ е маловажна, тъй като по дефиниция не може да причини проблем с целостта на данните. Разбира се, можете да имате код, който вмъква нов ред в TPM_INITIATIVES с нов INITIATIVEID , променете всички редове в дъщерната таблица, които препращат към стария ред, за да препращат към новия ред, след което модифицирайте стария ред. Но това няма да бъде уловено от нито едно от предложените решения.

Ако приложението ви е дефинирало дъщерни таблици, но не е декларирало подходящите ограничения на външния ключ, това би бил най-добрият начин за разрешаване на проблема.

Като се има предвид това, решението на Arnon за създаване на изглед трябва да работи. Ще преименувате таблицата, ще създадете изглед със същото име като съществуващата таблица и (евентуално) ще дефинирате ВМЕСТО задействане на изгледа, който просто никога няма да актуализира INITIATIVEID колона. Това не трябва да изисква промени в други части на приложението.

Можете също така да дефинирате тригер в таблицата

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;

Някой, разбира се, може да деактивира тригера и да издаде актуализация. Но предполагам, че не се опитвате да спрете нападател, а просто част от код с грешки.

Въз основа на описанието на симптомите, които виждате обаче, изглежда, че има по-голям смисъл да регистрирате хронологията на промените в колоните в тази таблица, за да можете действително да определите какво се случва, вместо да гадаете и да се опитвате да запушите дупки -по-един. Така че, например, можете да направите нещо подобно

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;

След това можете да направите заявка TPM_INITIATIVES_HIST за да видите всички промени, които са били направени в определен ред с течение на времето. Така че можете да видите дали стойностите на първичния ключ се променят или някой просто променя неключовите полета. В идеалния случай може да имате допълнителни колони, които можете да добавите към таблицата с хронологията, за да помогнете за проследяване на промените (т.е. може би има нещо от V$SESSION това може да е полезно).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да промените отрицателната стойност на положителна в Oracle?

  2. Получаване на първата възникнала стойност от XML чрез анализатор на oracle

  3. Преобразувайте всеки знак в низ в ред

  4. Regex за премахване на думи от черния списък от изречение

  5. Безопасно ли е да използвате ROWID за намиране на ред/запис в Oracle?