2010-08-09 4 views
2

프로젝트의 기록을 추적하기 위해 시스템 작업 중입니다. 주 테이블에는 프로젝트, 작업 및 클라이언트라는 세 개의 테이블이 있으며 각 테이블에 대해 세 개의 히스토리 테이블이 있습니다. 프로젝트 테이블에 다음과 같은 트리거가 있습니다.오라클 및 히스토리 만들기

CREATE OR REPLACE TRIGGER mySchema.trg_projectHistory 
BEFORE UPDATE OR DELETE 
ON mySchema.projects REFERENCING NEW AS New OLD AS Old 
FOR EACH ROW 
declare tmpVersion number; 
BEGIN 
    select myPackage.GETPROJECTVERSION(:OLD.project_ID) into tmpVersion from dual; 

    INSERT INTO mySchema.projectHistiry 
    (project_ID, ..., version) 
    VALUES 
    (:OLD.project_ID, 
    ... 
    tmpVersion 
    ); 

EXCEPTION 
WHEN OTHERS THEN 
    -- Consider logging the error and then re-raise 
    RAISE; 
END ; 
/

각 테이블 (프로젝트, 작업, 클라이언트)마다 3 개의 트리거가 있습니다.

여기에 도전 과제가 있습니다. 동시에 모든 것이 변경되는 것은 아닙니다. 예를 들어 누군가 특정 업무의 비용 만 업데이트 할 수 있습니다. 이 경우 하나의 트리거 만 실행되고 하나의 삽입이 발생합니다. 한 번에 3 개의 기록 테이블에 하나의 레코드를 삽입하고 싶습니다. 아무 것도 프로젝트 및 클라이언트 테이블에서 변경되지 않은 경우에도 마찬가지입니다.

누군가가 프로젝트의 end_date, 비용을 변경하고 다른 클라이언트를 선택하면 어떻게 될까요? 이제는 동시에 세 개의 트리거가 실행됩니다. 이 경우에만 세 개의 기록 테이블에 하나의 기록이 삽입됩니다. (원하는)

첫 번째 예제에서는 3 개의 테이블에 삽입 할 트리거를 수정하면 두 번째 예제가 발생할 때 9 개의 삽입이 생깁니다.

이 문제를 해결할 방법이 확실하지 않습니다. 어떤 도움?

답변

0

원래의 행이 변경되면 각 기록 행의 유효 기간과 종료일을 캡처하는 것처럼 보입니다.

예 : Project_hist 테이블에는 주어진 프로젝트의 시작 날짜와 종료 날짜가있는 eff_date와 exp_date가 있습니다. 프로젝트 테이블에는 유효 날짜가 있습니다. (활성 프로젝트이므로).

테이블 값 중 하나만 업데이트 된 경우 세 개의 기록 테이블에 대해 행을 삽입하려는 이유가 표시되지 않습니다. 현재 논리를 사용하여 원하는 날짜에 필요한 세부 정보를 얻을 수 있습니다. (갱신 된 테이블의 실행 기록 테이블에 이전 행만 삽입).

+0

사실,하지만 직면 한 다른 문제는 작업 기록이지만 프로젝트/클라이언트 기록은 없습니다. 나는 join을 알아 내야 만한다 : x_history에 아무것도 없다면, x에서 그것을 얻는다. – CFNinja

+0

글쎄요,이 경우, 히스토리 테이블에 활성 버전과 비활성 버전을 둘 다 사용해 볼 수 있습니까? 이 접근법의 단점은 작업 테이블의 현재 레코드를 업데이트 할 때마다 기록의 최신 레코드를 업데이트 한 다음 새 레코드를 삽입해야한다는 것입니다. –

+0

히스토리 테이블에는 비활성 버전 만 포함됩니다. 주 테이블에 대한 모든 갱신/삭제로 인해 비활성 실행 기록 버전이 작성됩니다. 후자는 어떻게합니까? x_history에 아무것도없는 경우 x에서 가져옵니다. – CFNinja

2

나에게 그것은 마치 테이블을 변경할 때마다 만들어진 세 테이블의 트랜잭션 수준 스냅 샷을 원하는 것처럼 들립니다.

프로젝트 ID와 선택적으로 클라이언트/태스크 ID를 사용하여 단일 패키지 프로 시저를 호출하는 세 개의 테이블 각각에 행 수준 트리거를 지정하십시오.

패키지 프로 시저는 해당 키와 트랜잭션에 대한 히스토리 레코드가없는 관련 프로젝트, 클라이언트 및 태스크를 세 개의 히스토리 테이블 모두에 삽입합니다 (즉, 중복을 원하지 않음). 후자에 관해서 몇 가지 선택 사항이 있습니다. 고유 한 제약 조건과 FORALL/SAVE EXCEPTIONS, DML 오류 로깅 (EXCEPTIONS INTO) 또는 INSERT ... SELECT ...와 같은 BULK 선택 및 삽입 중 하나를 사용할 수 있습니다 ... 선택 사항 ... 존재하지 않는 곳 ...

귀하의 거래를 추적하십시오. 나는 이것이 당신이 myPackage로하고 있었던 것 같아요 .GETPROJECTVERSION. 트릭은 새 트랜잭션이있을 때만 버전을 증가시키는 것입니다. 새 버전 번호를 얻었을 때 pacakge 수준의 변수에 저장하면 세션에 이미 버전 번호가 있는지 여부를 쉽게 알 수 있습니다.

세션이 여러 트랜잭션을 실행하는 경우 세션 수준 버전 번호가 이전 트랜잭션의 일부인 경우 '삭제'해야합니다. DBMS_TRANSACTION.LOCAL_TRANSACTION_ID를 가져 와서 패키지/세션 수준에 저장하면 새 트랜잭션 또는 동일한 트랜잭션의 일부인지 여부를 확인할 수 있습니다.

+0

질문의 기초가되는 유스 케이스 진단을위한 +1 – APC

+0

나중에 같은 트랜잭션에서 변경을 위해 merge를하고 싶다고 생각합니다. 'not exists '를 사용하면 한 테이블의 초기 변경 사항을 포함하고 다른 두 테이블을 무시한 스냅 샷이 생깁니다 (동일한 트랜잭션 내 첫 번째 테이블의 추가 변경 사항은 무시됩니다). – Allan

0

대체 대답. 살펴보기 Total Recall/Flashback Archive 보유 기간을 10 년으로 설정하고 간단한 AS OF TIMESTAMP를 사용하여 특정 타임 스탬프로 데이터를 가져올 수 있습니다.

성능에 대한 확신이 없습니다. 일일 또는 주간 보존이 더 쉬울 수 있으며 VERSIONS BETWEEN 구문을 사용하여 이전 버전을 선택하고 기록 테이블에 저장하는 별도의 예약 된 작업이 더 쉬울 수도 있습니다.

+0

라이센스 발급에 돈이 있다면 Total Recall이 가장 훌륭한 솔루션입니다. – APC