0

지금까지 필자는 추가 솔루션 (freenode의 #postgresql 덕분에)이 필요한 솔루션을 제안했습니다.SQL - DNS 레코드의 효율적인 버전 관리

내가 해결하려고하는 문제는 일종의 기록을 유지하면서 DNS 레코드를 저장하는 효율적인 방법입니다. 현재 내가 겪고있는 문제는 wCTE가 새로운 레코드를 삽입하고 이전 레코드를 올바르게 삭제하는 것입니다. 그러나 그것은 기록을 읽지 않습니다.

WITH deltas AS (
    SELECT o, n FROM (
     SELECT id, name, domain_id, class_id, addr FROM record WHERE tld_id = $1 
    ) AS o FULL OUTER JOIN record_temp n 
    ON (
     o.name = n.name AND 
     o.domain_id = n.domain_id AND 
     o.class_id = n.class_id AND 
     o.addr = n.addr 
    ) 
    WHERE (o.name, o.domain_id, o.class_id, o.addr) 
    IS DISTINCT FROM (n.name, n.domain_id, n.class_id, n.addr) 
), mark_dead AS (
    UPDATE record SET alive = FALSE 
    WHERE id IN (
     SELECT (o).id FROM deltas WHERE (o).id IS NOT NULL 
    ) RETURNING * 
) 
INSERT INTO record (name, domain_id, tld_id, class_id, addr) 
SELECT (n).name, (n).domain_id, (n).tld_id, (n).class_id, (n).addr 
FROM deltas WHERE 
    (n).name IS NOT NULL AND 
    (n).domain_id IS NOT NULL AND 
    (n).tld_id IS NOT NULL AND 
    (n).class_id IS NOT NULL AND 
    (n).addr IS NOT NULL 
; 

오 결과가 record_temp에 존재하지 않는 모든 이전의 기록을 가지고, n은 새로 삽입 할 필요가 모든 레코드가 다음 wCTE입니다. 두 테이블에 존재하는 결과 (내부 조인)를 가져 오는 또 다른 조인을 추가해야 할 필요가 있습니다.이 테이블은 죽은 것으로 표시된 경우 활성 상태로 표시해야합니다.

참조 스키마의 나머지 부분은 다음과 같습니다

CREATE TABLE record (
     id SERIAL, 
     name VARCHAR(255), 
     domain_id INT, 
     tld_id INT, 
     class_id INT, 
     addr INET, 
     alive BOOLEAN DEFAULT TRUE, 
     PRIMARY KEY (id), 
     CONSTRAINT fk1 FOREIGN KEY (domain_id) REFERENCES domain (id) MATCH SIMPLE, 
     CONSTRAINT fk2 FOREIGN KEY (tld_id) REFERENCES tld (id) MATCH SIMPLE, 
     UNIQUE(name, domain_id, class_id, addr) 
); 

    CREATE TABLE record_history (
     id SERIAL, 
     record_id INT, 
     history_type record_history_type, 
     stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
     CONSTRAINT fk1 FOREIGN KEY (record_id) REFERENCES record (id) MATCH SIMPLE, 
     PRIMARY KEY(id) 
); 

CREATE TEMP TABLE record_temp (
    name VARCHAR(255), 
    domain_id INT, 
    tld_id INT, 
    class_id INT, 
    addr INET, 
    UNIQUE(name, domain_id, class_id, addr) 
) 
ON COMMIT DROP; 

record_history 함수 및 트리거를 사용하여 채워집니다 그리고 나는 그것을 기대하는 방법을 채우고, 다음이 트리거는 다음과 같습니다

RETURNS TRIGGER AS $$ 
    BEGIN 
     INSERT INTO record_history (record_id, history_type) VALUES (NEW.id, 'added'); 
     RETURN NEW; 
     END; 
    $$ language 'plpgsql'; 

    RETURNS TRIGGER AS $$ 
    BEGIN 
     IF NEW.alive = OLD.alive THEN 
      RETURN NEW; 
     END IF; 
     IF NEW.alive THEN 
      INSERT INTO record_history (record_id, history_type) VALUES (NEW.id, 'added'); 
     END IF; 
     IF NOT NEW.alive THEN 
      INSERT INTO record_history (record_id, history_type) VALUES (NEW.id, 'deleted'); 
     END IF; 
     RETURN NEW; 
    END; 
    $$ language 'plpgsql'; 

    ON record FOR EACH ROW EXECUTE PROCEDURE 
     add_insert_record_history(); 

    ON record FOR EACH ROW EXECUTE PROCEDURE 
     add_update_record_history(); 
+2

제공된 업데이트 명령이 구문 적으로 잘못되었습니다. –

+0

죄송합니다. – jawr

+0

이 테이블에 히스토리 (또는 버전 관리)를 제공하려면 * 적어도 타임 스탬프 필드 중 하나가 키의 일부 여야합니다. – joop

답변

0

나는 것 다음 쿼리를 사용하여 내가 원하는 방식대로 작동하게하려면 매우 편리합니다.

WITH deltas AS (
     SELECT o, n FROM (
      SELECT id, name, domain_id, class_id, addr FROM record WHERE tld_id = $1 
     ) AS o FULL OUTER JOIN record_temp n 
     ON (
      o.name = n.name AND 
      o.domain_id = n.domain_id AND 
      o.class_id = n.class_id AND 
      o.addr = n.addr 
     ) 
     WHERE (o.name, o.domain_id, o.class_id, o.addr) 
     IS DISTINCT FROM (n.name, n.domain_id, n.class_id, n.addr) 
    ), mark_dead AS (
     UPDATE record SET alive = FALSE 
     WHERE id IN (
      SELECT (o).id FROM deltas WHERE (o).id IS NOT NULL 
     ) RETURNING * 
    ), mark_alive AS (
     UPDATE record SET alive = TRUE 
     WHERE alive = FALSE AND id IN (
      SELECT id FROM (
       SELECT id, name, domain_id, class_id, addr FROM record WHERE tld_id = $1 
      ) AS o INNER JOIN record_temp n 
      ON (
       o.name = n.name AND 
       o.domain_id = n.domain_id AND 
       o.class_id = n.class_id AND 
       o.addr = n.addr 
      ) 
     ) RETURNING * 
    ) 
    INSERT INTO record (name, domain_id, tld_id, class_id, addr) 
    SELECT (n).name, (n).domain_id, (n).tld_id, (n).class_id, (n).addr 
    FROM deltas WHERE 
     (n).name IS NOT NULL AND 
     (n).domain_id IS NOT NULL AND 
     (n).tld_id IS NOT NULL AND 
     (n).class_id IS NOT NULL AND 
     (n).addr IS NOT NULL 
    ;