2016-08-13 3 views
1

a의 행이 삽입, 업데이트 또는 삭제 될 때마다 b에 해당 행을 삽입, 업데이트 또는 삭제하는 테이블이 a이고 3 개의 트리거가 있습니다. 3 개의 트리거 모두 동일한 트리거 기능 p을 사용합니다.PostgreSQL 트리거 함수에 대한 if 문을 조인

CREATE OR REPLACE FUNCTION p() 
RETURNS TRIGGER 
AS $$ 
BEGIN 
    IF (TG_OP = 'INSERT') THEN 
    -- INSERT INTO b ... 
    RETURN NEW; 
    ELSIF (TG_OP = 'UPDATE') THEN 
    -- UPDATE b ... 
    RETURN NEW; 
    ELSIF (TG_OP = 'DELETE') THEN 
    -- DELETE FROM b ... 
    RETURN NEW; 
    ELSE 
    RETURN NULL; 
    END IF; 
END; 
$$ LANGUAGE PLPGSQL; 

CREATE TRIGGER i AFTER INSERT ON a FOR EACH ROW EXECUTE PROCEDURE p(); 
CREATE TRIGGER u AFTER UPDATE ON a FOR EACH ROW EXECUTE PROCEDURE p(); 
CREATE TRIGGER d AFTER DELETE ON a FOR EACH ROW EXECUTE PROCEDURE p(); 

a도있는 외부 키 a1c 및 I는 그것이 IF/ELSIF 분기도 c의 열 c2에 따라 입사하는 방식 p을 변경하고자하는 (기본 키 c1)와 : 조인 된 열이 변경된 경우 INSERTUPDATE 가지를 입력하십시오. 동일하게 유지되면 UPDATE 분기를 입력하십시오. 이 같은 효과에 뭔가 : oldCnewC가 발생할 것

IF (TG_OP = 'INSERT') OR ((TG_OP = 'UPDATE') AND (oldC.c2 <> newC.c2)) THEN 
    -- ... 
    ELSIF (TG_OP = 'UPDATE') OR (oldC.c2 = newC.c2) THEN 
    -- ... 
    ELSIF (TG_OP = 'DELETE') OR ((TG_OP = 'UPDATE') AND (oldC.c2 <> newC.c2)) THEN 
    -- ... 
    ELSE 
    -- ... 
    END IF; 

다음과 유사한 조인 (약와 구문.) : 그래서

SELECT oldC.* FROM a, c AS oldC WHERE OLD.a1 = c.c1; 
SELECT newC.* FROM a, c AS newC WHERE NEW.a1 = c.c1; 

효과에 필요한 것을 두 개의 외부 조인 IF 문을 사용하면 oldCnewC (또는 이와 유사한 내용)을 참조 할 수 있습니다. 이게 가능하며 p의 변경된 버전은 (올바른 PostgreSQL 구문으로) 어떻게 표시됩니까?

답변

3

먼저 DELETE의 경우 NEW이 없으므로 RETURN NEW;은 의미가 없으므로 예외가 발생합니다. 상관 없어요. 당신은 AFTER에 대해 반환합니다. 함께있을 수도 있습니다 RETURN NULL;

다음은 INSERT 인 경우 OLD을 참조 할 수 없습니다. OLD 또는 NEW이라고 말하면서 전에 확인해야합니다.

그리고 당신은 단지 하나의 트리거 당신이 지금 그것을 가지고있는 방법이 필요합니다 :

CREATE TRIGGER a_i_u_d -- *one* trigger 
AFTER INSERT OR UPDATE OR DELETE ON a 
FOR EACH ROW EXECUTE PROCEDURE p(); 

그러나 , 내가 제안을 별도의 트리거 기능에 대한 INSERT, UPDATE 및 합병증을 피하기 위해 DELETE. 그런 다음 각각의 트리거 기능을 호출하는 세 개의 개별 트리거가 필요합니다.

추가하려는 경우 에만 UPDATE에 영향을 미칠 수 있습니다. INSERT 또는 DELETE으로 설명하는 것처럼 '변경'할 수있는 것은 없습니다. c의 열 c2에 따라

:

그리고 엄격하게 당신을 위해 무엇을 물어 말하기는 불가능 심지어 UPDATE 트리거입니다 열이 변경에 가입하면 ...

트리거 기능은 테이블 a은 테이블 c단일 스냅 샷을 본다. 해당 테이블에서 "변경"을 감지 할 수있는 방법은 없습니다. 당신은 정말 쓰기 의미하는 경우 :

을 열 a.a1에 따라 : 참조 된 값 c.c2 지금 다른 수 있도록 그 변경 한 경우 ...

는 .. 다음 방법이있다 :

트리거는 무한 루프와 다른 합병증이 적기 때문에 BEFORE UPDATE 트리거를 보여줍니다. ...

트리거

CREATE OR REPLACE FUNCTION p_upbef() 
    RETURNS trigger AS 
$func$ 
BEGIN 
    IF NEW.a1 <> OLD.a1 THEN -- assuming a1 is defined NOT NULL 
     IF (SELECT count(DISTINCT c.c2) > 1 -- covers possible NULL in c2 as well 
      FROM c 
      WHERE c.c1 IN (NEW.a1, OLD.a1)) THEN 
      -- do something 
     END IF; 
    END IF; 

    RETURN NEW; 
END 
$func$ LANGUAGE plpgsql; 

a1 경우는 NULL이 될 수 있으며, 당신은 더 많은 일을해야 할뿐만 아니라 NULL로 /에서 변경 내용을 추적해야합니다 : (. AFTER로 변경하면 간단하다)

CREATE TRIGGER upbef 
BEFORE UPDATE ON a 
FOR EACH ROW EXECUTE PROCEDURE p_upbef(); 

모든 것을 (그리고 트리거에서 다른 일이없는) 지금 a.a1의 변화에 ​​의존하기 때문에 당신은 트리거 자체에 외부 IF (싼)를 이동할 수 있습니다

CREATE OR REPLACE FUNCTION p_upbef() 
    RETURNS trigger AS 
$func$ 
BEGIN 
    IF (SELECT count(DISTINCT c.c2) > 1 -- covers NULL as well 
     FROM c 
     WHERE c.c1 IN (NEW.a1, OLD.a1)) THEN -- assuming a1 is NOT NULL! 
     -- do something 
    END IF; 

    RETURN NEW; 
END 
$func$ LANGUAGE plpgsql; 

트리거 :

CREATE TRIGGER upbef 
BEFORE UPDATE OF a1 ON a 
FOR EACH ROW EXECUTE PROCEDURE p_upbef();

실제로 변경되지 않은 값을 떠날 수있는 열 a1을과 관련된 UPDATE때문에, 정확히 같은 아니지만, 충분히 우리의 목적을 위해 어느 쪽이든 좋은 : 해당 사례의 c.c2에 대해서만 비싼 수표를 사용하십시오..

관련 :

+0

하나는 올바른 "(내가 처음 해석을 지원하기 위해 c''에/사람 같아 트리거를 배치해야한다고 가정하는 것입니다 c2에 따라 c2 열에 따라 달라집니다 : 조인 된 열이 변경된 경우 ")? – Drux

+1

@Drux : 예,'c.c2'의 변경을 감시하려면'c'에 트리거가 필요합니다. 너무 많은 트리거가있는 무한 루프를 만들지 않도록 조심하십시오. 때로는 데이터 수정 CTE를 사용하는 조합 된 쿼리가 좋은 대안입니다. [예제.] (http://stackoverflow.com/questions/20561254/insert-data-in-3-tables-at-a-time-using-postgres/20561627#20561627) –