database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
ㆍPostgreSQL
Firebird
Oracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
PostgreSQL Q&A 7536 게시물 읽기
No. 7536
[답변 감사합니다]Trigger관련 다시 정리해서 질문드립니다.
작성자
김상희
작성일
2008-10-08 11:49
조회수
6,668

안녕하세요. 

어제 답글주신분 너무 감사드립니다.

저녁에 DB가 연결이 안되서 정확한 커리문을 기재하지 못했습니다.

다시 문제사항을 정리 했습니다.

-- 문제의 요점은 아래와 같습니다.

1. 먼저 test_tb를 생성합니다. -> 부모가 될 테이블 입니다.

-- drop table test_tb cascade;

CREATE TABLE test_tb

(

  name character varying(10),

  capture_time timestamp without time zone

)

WITH (OIDS=FALSE);

ALTER TABLE test_tb OWNER TO atms;

-- Index: idx2_capture_test_tb

-- DROP INDEX idx2_capture_test_tb;

CREATE INDEX idx2_test_tb

  ON capture_test_tb

  USING btree

  (capture_time);



2. 자식 테이블을 상속 받아서 생성합니다.

-- child 생성

CREATE TABLE test_20081007_tb_00 (

    CHECK ( capture_time >= TIMESTAMP '2008-10-07 00:00:00' AND capture_time < TIMESTAMP '2008-10-07 12:00:00' )

) INHERITS (test_tb);

CREATE TABLE test_20081007_tb_01 (

    CHECK ( capture_time >= TIMESTAMP '2008-10-07 12:00:00' AND capture_time < TIMESTAMP '2008-10-08 00:00:00' )

) INHERITS (test_tb);

3. child에 테이블에 인덱스를 생성합니다.

CREATE  INDEX idx_test_20081007_tb_00 ON test_20081007_tb_00 (capture_time);

CREATE  INDEX idx_test_20081007_tb_01 ON test_20081007_tb_01 (capture_time);


4. 트리거 함수를 생성합니다.

CREATE OR REPLACE FUNCTION func_test_tb_today()

RETURNS TRIGGER AS $$

BEGIN

    IF ( NEW.capture_time  >= TIMESTAMP '2008-10-07 00:00:00' AND NEW.capture_time < TIMESTAMP '2008-10-07 12:00:00' )

    THEN

        INSERT INTO test_20081007_tb_00 VALUES (NEW.*);

    ELSIF ( NEW.capture_time  >= TIMESTAMP '2008-10-07 12:00:00' AND NEW.capture_time  < TIMESTAMP '2008-10-08 00:00:00' )

    THEN

        INSERT INTO test_20081007_tb_01 VALUES (NEW.*);

    ELSE

        RAISE EXCEPTION 'Date out of range.  Fix the func_test_tb_today() function!';

    END IF;

    RETURN NULL;

END;

$$

LANGUAGE plpgsql;


5. 트리거를 생성합니다.


CREATE TRIGGER tri_func_test_tb_today

    BEFORE INSERT ON test_tb

    FOR EACH ROW EXECUTE PROCEDURE func_test_tb_today();



6. 태스트 Insert구문 실행

INSERT INTO test_tb(

            "name", capture_time)

    VALUES ('test', '2008-10-07 12:00:00');



요기 까지는 무리 없이 진행이 됩니다. 하지만 프로젝트 진생상 내일꺼 Child테이블을 미리 만들어 놔야 합나다.

그래서 오늘 날짜에 미리 아래와 같이 내일꺼 Child 테이블을 만들었습니다.



7. 내일꺼 Child생성

CREATE TABLE test_20081008_tb_00 (

    CHECK ( capture_time >= TIMESTAMP '2008-10-08 00:00:00' AND capture_time < TIMESTAMP '2008-10-08 12:00:00' )

) INHERITS (test_tb);

CREATE TABLE test_20081008_tb_01 (

    CHECK ( capture_time >= TIMESTAMP '2008-10-08 12:00:00' AND capture_time < TIMESTAMP '2008-10-09 00:00:00' )

) INHERITS (test_tb);



8.내일꺼 Index 생성

CREATE  INDEX idx_capture_20081008_test_tb_00 ON test_20081008_tb_00 (capture_time);

CREATE  INDEX idx_capture_20081008_test_tb_01 ON test_20081008_tb_01 (capture_time);



9. 내일꺼 트리거 함수 생성


CREATE OR REPLACE FUNCTION func_test_tb_tomorrow()

RETURNS TRIGGER AS $$

BEGIN

    IF ( NEW.capture_time  >= TIMESTAMP '2008-10-08 00:00:00' AND NEW.capture_time < TIMESTAMP '2008-10-08 12:00:00' )

    THEN

        INSERT INTO capture_20081008_test_tb_00 VALUES (NEW.*);

    ELSIF ( NEW.capture_time  >= TIMESTAMP '2008-10-08 12:00:00' AND NEW.capture_time  < TIMESTAMP '2008-10-09 00:00:00' )

    THEN

        INSERT INTO capture_20081008_test_tb_01 VALUES (NEW.*);

    ELSE

        RAISE EXCEPTION 'Date out of range.  Fix the func_test_tb() unction!';

    END IF;

    RETURN NULL;

END;

$$

LANGUAGE plpgsql;



10. 내얼꺼 트리거 생성


CREATE TRIGGER tri_func_test_tb_tomorrow

    BEFORE INSERT ON test_tb

    FOR EACH ROW EXECUTE PROCEDURE func_test_tb_tomorrow();


------------------ 작업 끝..

위와같이 작업 한 후.

INSERT INTO test_tb(

            "name", capture_time)

    VALUES ('test', '2008-10-07 12:00:00');

위 커리문은 인서트가 잘 됩니다.


하지만 날짜를 바꿔서 insert하면..(아래)

INSERT INTO test_tb(

            "name", capture_time)

    VALUES ('test', '2008-10-08 12:00:00');

'Date out of range.  Fix the func_test_tb_today() function!' 라는 경고메시지가 뜨고 Insert가 되지 않습니다.

트리거 함수가2개 등록되어 있는데 왜 하나만 인식할까요??

해결 방법은 있을까요?

여러 고수님들 다시 한번 좋은 답변 부탁드립니다.

그럼 수고하세요..

이 글에 대한 댓글이 총 5건 있습니다.

데이터가 중복으로 들어가지더라도 각 트리거 함수의 리턴을

RETURN NULL; 말고 RETURN new; 해보세요. 그래도 하나만 동작하려나요?;;

 

신기배(소타)님이 2008-10-08 12:10에 작성한 댓글입니다.

음... 알려주신데로 각 함수의 reuturn 값을 NULL 에서 NEW로 변경해줬습니다.

그랬더니 데이터는 잘 들어가지더라구요...


그런데 부모 테이블에는 값이 중복으로 들어갑니다..


결론을 말하면.. 데이터를 하나 insert 했는데..


커리를 하면 2개가 중복으로 나오게 된겁니다.


중복이 허용 안되고 해결할 수 있는 방법은 없을까요?


다시 한번 부탁드립니다..


그럼 수고하세요..

김상희님이 2008-10-08 13:41에 작성한 댓글입니다. Edit

트리거 함수가 return null 해버리면 그 다음에 처리할 트리거가 처리할 row 가 사라지기 때문인데요.


이렇게 해보시지요?


4. 트리거 함수를 생성합니다.

 

CREATE OR REPLACE FUNCTION func_test_tb_today()

RETURNS TRIGGER AS $$

 

BEGIN

 

    IF ( NEW.capture_time  >= TIMESTAMP '2008-10-07 00:00:00' AND NEW.capture_time < TIMESTAMP '2008-10-07 12:00:00' )

 

    THEN

 

        INSERT INTO test_20081007_tb_00 VALUES (NEW.*);

        RETURN NULL;

 

    ELSIF ( NEW.capture_time  >= TIMESTAMP '2008-10-07 12:00:00' AND NEW.capture_time  < TIMESTAMP '2008-10-08 00:00:00' )

 

    THEN

 

        INSERT INTO test_20081007_tb_01 VALUES (NEW.*);

        RETURN NULL;

 

    ELSE

 

        RAISE EXCEPTION 'Date out of range.  Fix the func_test_tb_today() function!';

 

    END IF;

 

    RETURN NEW;

END;

 

$$

 

LANGUAGE plpgsql;

 

9. 내일꺼 트리거 함수 생성

 

 

CREATE OR REPLACE FUNCTION func_test_tb_tomorrow()

 

RETURNS TRIGGER AS $$

 

BEGIN

 

    IF ( NEW.capture_time  >= TIMESTAMP '2008-10-08 00:00:00' AND NEW.capture_time < TIMESTAMP '2008-10-08 12:00:00' )

 

    THEN

 

        INSERT INTO capture_20081008_test_tb_00 VALUES (NEW.*);

 

    ELSIF ( NEW.capture_time  >= TIMESTAMP '2008-10-08 12:00:00' AND NEW.capture_time  < TIMESTAMP '2008-10-09 00:00:00' )

 

    THEN

 

        INSERT INTO capture_20081008_test_tb_01 VALUES (NEW.*);

        RETURN NULL;

    ELSE

 

        RAISE EXCEPTION 'Date out of range.  Fix the func_test_tb() unction!';

 

    END IF;

 

    RETURN NEW;

 

END;

 

$$

 

LANGUAGE plpgsql;


이런식으로 데이터가 삽입 되었을 때는 reutrn null 해서 다음 트리거가 동작하지 않게 하고 삽입이 안되었을 때는 return new 해서 다음 트리거가 동작하게 하고요.

근데 이렇게 트리거가 계속 늘어나는 것 보다는 하나의 트리거로 스마트하게 동작하도록 고려하는 것이 앞으로 좋지 않을까요 ㅋ

아니면 지나간 트리거는 삭제해야 하는 관리 부담이 생겨날 것 같네요

 

신기배(소타)님이 2008-10-08 14:17에 작성한 댓글입니다.
이 댓글은 2008-10-08 14:18에 마지막으로 수정되었습니다.

신기배(소타)님 답변 갑사드립니다.


제가 워낙 DB에 대한 기본이 없어서..


우선 하나의 트리거 함수로 처리하는것은 다시 생각해 봐야할꺼 같아요..


일단 소개해준 내용대로 인서트를 실행한 결과는 만족스럽게 들어갑니다..


앞으로 공부를 더 해야할듯 해요..^^


답변 감사드리고 좋은일 많이 생기시길 바랄께요..


그럼 수고하세요..

김상희님이 2008-10-08 14:26에 작성한 댓글입니다. Edit

굳이 테이블 두개 생성할 때마다 트리거 하나씩 생성할 필요가 있나요?


그냥 동적쿼리 만들면 안 되나요?


xxx_today() 가 정상적으로 된다고 ??니 그것을 참고로 만들어봤습니다.

소스코드는 대략 이렇습니다.

특정한 날짜가 들어오면 먼저 날짜에맞는 테이블에 insert 해보고

에러나면 테이블이 존재하지 않는 것이기에 (꼭 그런건 아니지만)

해당 테이블을 생성하고 다시 insert 시도

에러없으면 insert 가 된거니깐 종료하는 것입니다.

테스트는 안 해봤으므로 에러나 오동작이 있을 수 있습니다.


CREATE OR REPLACE FUNCTION func_test_tb ()

RETURNS TRIGGER AS

$$

  declare

    v_tb text;

    v_am text;

    v_time1 text;

    v_time2 text;

    v_query text;

    v_tmp text;

    v_code smallint;

  BEGIN

    if to_char(NEW.capture_time, 'AM') = 'AM' then

        v_am := '00';

        v_time1 := '00:00:00';

        v_time2 := '11:59:59';

    else

        v_am := '01';

        v_time1 := '12:00:00';

        v_time2 := '23:59:59';

    end if;

    v_code := 0;

    v_tb := 'test_' || to_char(NEW.capture_time, 'YYYYMMDD') || '_tb_' || v_am;

    v_query := 'insert into ' || v_tb || ' values (NEW.*);

    loop

        -- table not found

        if v_code = 2 then

            v_tmp = 'create table ' || v_tb || ' (

                        check (to_char(capture_time, 'HH24:MI:SS') between ' || v_time1 || ' and ' || v_time2 || ')

                     ) inherits (test_tb)';

            excute v_tmp;

            v_tmp := 'create index idx_' || v_tb || ' on ' || v_tb || ' (capture_time)';

            execute v_tmp;

            execute v_query;

            return null;

        elsif v_code = 1 then

            return null;

        end if;

        v_code := 1;

        execute v_query;

        exception when undefined_table then

            v_code := 2;

    end loop;

  END;

$$ LANGUAGE plpgsql;

 

tyro님이 2008-10-09 15:10에 작성한 댓글입니다.
이 댓글은 2008-10-09 15:12에 마지막으로 수정되었습니다. Edit
[Top]
No.
제목
작성자
작성일
조회
7539AS 생략 안되나요? [1]
post
2008-10-10
6190
7538초보적인 질문입니다~ [2]
관식
2008-10-08
7022
7537insert & import 속도 [6]
박성식
2008-10-08
7210
7536[답변 감사합니다]Trigger관련 다시 정리해서 질문드립니다. [5]
김상희
2008-10-08
6668
7535trigger함수 관련 질문입니다. [2]
김상희
2008-10-08
6120
7534자바 rmi서버를 이용하는데 디비에 접근하지 못합니다.
김치원
2008-10-07
6309
7533로그인문제입니다 [1]
변승찬
2008-10-06
6289
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.019초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다