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).