0

テーブル内の関連レコードの履歴を追跡できるようにしたいと考えています。Oracle システムでは、既知の場合は元のレコードの PK を、元の PK が指定されていない場合は新しい PK をフィールドに入力する挿入トリガーを作成することで、これを実現しました。

つまり、次のコードの場合、INS_Nomination トリガーは、新しい Nomination.parent_nomination_id フィールドに、受信した parent_nomination_id を入力するか、parent_nomination_id が NULL の場合はテーブルの PK (nomination_id) に対して生成された値を入力します。

/*create nomination tables*/
    CREATE TABLE Nomination (
        nomination_id NUMBER(12,0) NOT NULL ENABLE, 
        parent_nomination_id NUMBER(12,0) NOT NULL, 
        whatever VARCHAR2(400 BYTE), 
        created_by NUMBER(12,0) NOT NULL ENABLE, 
        created_date DATE DEFAULT SYSDATE NOT NULL ENABLE, 
        active_ind NUMBER(1,0) DEFAULT 1 NOT NULL ENABLE, 
        CONSTRAINT Nomination_PK PRIMARY KEY (nomination_id) ENABLE
    );

    CREATE INDEX Nomination_INDEX1 ON Nomination (parent_nomination_id, active_ind DESC) ;

    CREATE UNIQUE INDEX Nomination_PK ON Nomination (nomination_id);

    CREATE SEQUENCE Nomination_SEQ;

    CREATE OR REPLACE TRIGGER INS_Nomination BEFORE INSERT ON Nomination FOR EACH ROW 
    BEGIN   
        SELECT Nomination_SEQ.nextval
        INTO :new.nomination_id 
        FROM Dual;

        SELECT NVL(:NEW.parent_nomination_id, :NEW.nomination_id)
        INTO :NEW.parent_nomination_id
        FROM Dual;
    END;

    /
    ALTER TRIGGER INS_Nomination ENABLE;

Postgres でこれと同じ機能を実現するにはどうすればよいですか?

4

1 に答える 1

2
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE nomination 
      ( nomination_id BIGSERIAL NOT NULL PRIMARY KEY
      , parent_nomination_id BIGINT NOT NULL
         REFERENCES nomination(nomination_id)
      , whatever VARCHAR
      , created_by INTEGER NOT NULL DEFAULT 0
      , created_date DATE NOT NULL DEFAULT CURRENT_DATE
      , active_ind boolean NOT NULL DEFAULT true
    );

CREATE OR REPLACE FUNCTION nomination_fix_parent() RETURNS TRIGGER
AS
$func$
        BEGIN
         NEW.parent_nomination_id := NEW.nomination_id ;
         RETURN NEW;
        END
$func$ LANGUAGE plpgsql ; 

CREATE TRIGGER nomination_fix_parent
    BEFORE INSERT ON nomination
    FOR EACH ROW
    WHEN (NEW.parent_nomination_id IS NULL)
    EXECUTE PROCEDURE nomination_fix_parent()
        ; 

-- Test it ...
INSERT INTO nomination(whatever) VALUES('First?' );
INSERT INTO nomination(parent_nomination_id, whatever) VALUES(1,'Second?' );
INSERT INTO nomination(nomination_id, parent_nomination_id, whatever) VALUES(5,1,'Five?' );
SELECT * FROM nomination;

-- after entering the third record with id=5, the sequence is out of sequence ...
SELECT currval('nomination_nomination_id_seq');

-- Re-adjust the value for the sequence
SELECT setval('nomination_nomination_id_seq', (SELECT MAX(nomination_id) FROM nomination) );

INSERT INTO nomination(whatever) VALUES('Fourth?' );
SELECT * FROM nomination;

ノート:

  • PRIMARY KEY句は自動的にREFERENCESインデックスを作成します
  • SERIALシーケンスをBIGSERIAL自動的に作成し、その nextval() をデフォルトとして使用します
  • DEFAULTしたがって、上記のフラグメントのトリガーは、シーケンスに基づくのではなく、同じ行の nomination_id (おそらくシーケンスに基づく) に基づいて、parent_nomination_id のa を設定するためにのみ必要です。
  • 手動で値を SERIAL/bigserial 列に挿入しても、シーケンスは変化しません。そのため、後で明示的に再同期する必要があります(を使用setval('nomination_id_seq', select max() from ...))。
于 2013-09-13T11:16:10.543 に答える