Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Jaki jest najłatwiejszy sposób na zrobienie kolumny READONLY w Oracle?

Jeśli istnieją tabele podrzędne wypełnione danymi, które odwołują się do INITIATIVEID kolumna Oracle powinna automatycznie utrudnić zmianę wartości klucza podstawowego, uniemożliwiając tworzenie wierszy osieroconych przez zmianę klucza podstawowego rodzica. Na przykład, jeśli istnieje tabela podrzędna, która ma ograniczenie klucza obcego do TPM_INITIATIVES i istnieje wiersz w tej tabeli podrzędnej z INITIATIVEID 17, nie będzie można zmienić INITIATIVEID wiersza w TPM_INITIAITVES tabela, której aktualna wartość wynosi 17. Jeśli w żadnej tabeli podrzędnej nie ma wiersza, który odwołuje się do konkretnego wiersza w TPM_INITIATIVES tabeli, można zmienić wartość, ale prawdopodobnie, jeśli nie ma relacji, zmiana wartości klucza podstawowego jest nieistotna, ponieważ z definicji nie może powodować problemu z integralnością danych. Oczywiście możesz mieć kod, który wstawia nowy wiersz do TPM_INITIATIVES z nowym INITIATIVEID , zmień wszystkie wiersze w tabeli podrzędnej, które odwołują się do starego wiersza, aby odwoływały się do nowego wiersza, a następnie zmodyfikuj stary wiersz. Ale to nie zostanie uwięzione przez żadne z proponowanych rozwiązań.

Jeśli aplikacja ma zdefiniowane tabele podrzędne, ale nie zadeklarowała odpowiednich ograniczeń klucza obcego, byłby to najlepszy sposób rozwiązania problemu.

Biorąc to pod uwagę, rozwiązanie Arnona dotyczące tworzenia widoku powinno działać. Zmieniłbyś nazwę tabeli, utworzył widok o tej samej nazwie co istniejąca tabela i (potencjalnie) zdefiniował wyzwalacz INSTEAD OF w widoku, który po prostu nigdy nie zaktualizuje INITIATIVEID kolumna. To nie powinno wymagać zmian w innych bitach aplikacji.

Możesz także zdefiniować wyzwalacz na stole

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;

Ktoś mógłby oczywiście wyłączyć wyzwalacz i wydać aktualizację. Ale zakładam, że nie próbujesz powstrzymać napastnika, tylko błędny fragment kodu.

Jednak w oparciu o opis objawów, które widzisz, bardziej sensowne wydaje się rejestrowanie historii zmian w kolumnach w tej tabeli, aby można było faktycznie określić, co się dzieje, zamiast zgadywać i próbować zatykać dziury. -po jednym. Na przykład możesz zrobić coś takiego

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;

Następnie możesz zapytać TPM_INITIATIVES_HIST aby zobaczyć wszystkie zmiany, które zostały wprowadzone w określonym wierszu w czasie. Możesz więc zobaczyć, czy zmieniają się wartości klucza podstawowego, czy też ktoś zmienia tylko pola niebędące kluczami. W idealnym przypadku możesz mieć dodatkowe kolumny, które możesz dodać do tabeli historii, aby pomóc w śledzeniu zmian (tzn. być może jest coś z V$SESSION to może być przydatne).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak utworzyć nie zerowe ograniczenie w Oracle?

  2. Jak rozwiązywać problemy z ORA-02049 i ogólnie blokować problemy z Oracle?

  3. łącząca wyrocznię z r

  4. Instrukcja ACCEPT w Oracle PL SQL

  5. Zmień rozmiar nazw tabel/kolumn/indeksów w Oracle 11g lub 12c