sql >> データベース >  >> RDS >> Oracle

このトリガーをOracleSQLに実装するにはどうすればよいですか?

    以前の試行で何が失敗したかについていくつかの詳細を把握するのに役立つという投稿されたコメントに同意します。また、TRIGGERを使用しないことをお勧めします。
    しかし、これは勉強の練習のためのものなので、ここに出発点となるかもしれないいくつかの例があります。

    NULLを許可しないようにテーブルを変更しました PRIMARY KEY これらの例では。

    開始するには、テーブルを作成します:

    CREATE TABLE CLIENTS (
      CLIENTID    VARCHAR2(15) NOT NULL,
      DNI         VARCHAR2(9),
      NAME        VARCHAR2(100) NOT NULL,
      SURNAME     VARCHAR2(100) NOT NULL,
      SEC_SURNAME VARCHAR2(100),
      EMAIL       VARCHAR2(100) NOT NULL,
      PHONEN      NUMBER(12),
      BIRTHDATE   DATE,
      CONSTRAINT PK_CLIENTS PRIMARY KEY (CLIENTID),
      CONSTRAINT UK1_CLIENTS UNIQUE (DNI),
      CONSTRAINT UK2_CLIENTS UNIQUE (EMAIL),
      CONSTRAINT UK3_CLIENTS UNIQUE (PHONEN)
    );
    
    CREATE TABLE CONTRACTS (
      CONTRACTID    VARCHAR2(10) NOT NULL,
      CLIENTID      VARCHAR2(15) NOT NULL,
      STARTDATE     DATE          NOT NULL,
      ENDDATE       DATE,
      CONTRACT_TYPE VARCHAR2(50),
      ADDRESS       VARCHAR2(100) NOT NULL,
      TOWN          VARCHAR2(100) NOT NULL,
      ZIPCODE       VARCHAR2(8)   NOT NULL,
      COUNTRY       VARCHAR2(100) NOT NULL,
      CONSTRAINT PK_CONTRACTS PRIMARY KEY (CONTRACTID),
      CONSTRAINT FK_CONTRACTS1 FOREIGN KEY (CLIENTID) REFERENCES CLIENTS
    );
    

    次に、最初のCLIENTを作成します s:

    INSERT INTO CLIENTS VALUES (1,NULL,'Frodo','Baggins',NULL,'[email protected]',NULL,NULL);
    INSERT INTO CLIENTS VALUES (2,NULL,'Chewbacca','UNKNOWN',NULL,'[email protected]',NULL,NULL);
    COMMIT;
    

    次に、TRIGGERを作成します 。この最初の例では、TRIGGER AFTER STATEMENTです タイプ。
    シンプルですが、すべてを評価するため非効率的です。 CLIENTINSERTの後 ステートメント。
    大規模なデータセットに対して、または複数のTRIGGERに直面した場合 s、これは問題になる可能性があります。
    このTRIGGER 以前の契約を確認し、そのENDDATEを設定します 無効の場合、または新しい契約の開始後の場合は、新しい契約の1日前まで。

    CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
      AFTER INSERT ON CONTRACTS
      BEGIN
        MERGE INTO CONTRACTS
        USING (
                SELECT CONTRACTID,
                  CANDIDATE_ENDDATE AS ENDDATE
                FROM
                  (SELECT CONTRACTS.CONTRACTID,
                     (TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
                     DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
                   FROM CONTRACTS)
                WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
        ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
        WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
        WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
      END;
      /
    

    次に、それをテストします。
    最初の契約を追加します。これらは最初のものであるため、終了日の変更は予想されません。ここでのフロドの契約には、すでに終了日が設定されています。

    INSERT INTO CONTRACTS VALUES('Break-Ring',1,TO_DATE('19560511','YYYYMMDD'), TO_DATE('19851014','YYYYMMDD'), NULL, 'No 1', 'Doom Mountain', 'MORD', 'Middle-Earth');
    INSERT INTO CONTRACTS VALUES('SaveGalaxy',2,TO_DATE('19770615','YYYYMMDD'), NULL, NULL, 'No 75', 'Rwookrrorro', 'RWKR', 'Kashyyyk');
    
    SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
    CONTRACTID  CLIENTID  STARTDATE  ENDDATE    
    Break-Ring  1         11-MAY-56  14-OCT-85  
    SaveGalaxy  2         15-JUN-77             
    

    次に、新しい契約を追加します。
    フロドの新しい契約は、既存の契約が終了する前に開始されるため、終了日が調整されます。
    チューバッカの最初の契約には終了日がなかったため、同様に調整されます。

    >
    INSERT INTO CONTRACTS VALUES('GoBackHome',1,TO_DATE('19570219','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
    INSERT INTO CONTRACTS VALUES('DefendHoth',2,TO_DATE('19801115','YYYYMMDD'), NULL, NULL, 'Meteor Crater', 'Ice Ridge', 'METEO', 'Hoth');
    SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
    CONTRACTID  CLIENTID  STARTDATE  ENDDATE    
    Break-Ring  1         11-MAY-56  18-FEB-57  
    GoBackHome  1         19-FEB-57             
    SaveGalaxy  2         15-JUN-77  14-NOV-80  
    DefendHoth  2         15-NOV-80             
    

    そして、他の契約が署名されると、パターンは続きます:

    INSERT INTO CONTRACTS VALUES('GoWedding',2,TO_DATE('19830309','YYYYMMDD'), NULL, NULL, 'Main Hall', 'Grand Palace', 'ALLNC', 'Coruscant');
    INSERT INTO CONTRACTS VALUES('Gardening',1,TO_DATE('19570503','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
    SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
    CONTRACTID  CLIENTID  STARTDATE  ENDDATE    
    Break-Ring  1         11-MAY-56  18-FEB-57  
    GoBackHome  1         19-FEB-57  02-MAY-57  
    Gardening   1         03-MAY-57             
    SaveGalaxy  2         15-JUN-77  14-NOV-80  
    DefendHoth  2         15-NOV-80  08-MAR-83  
    GoWedding   2         09-MAR-83             
    

    このクエリのワークロードを安定させるために、代わりにCOMPOUNDTRIGGERを使用できます。この2番目の例では、最初の例と同じ結果が得られますが、CONTRACTに問い合わせるだけです。 CLIENTのs 変更された:

    まず、ROLLBACK; 次に、TRIGGERで使用するタイプを作成します :

    CREATE OR REPLACE TYPE NUMBER_LIST IS TABLE OF NUMBER;
    /
    

    次に、COMPOUND TRIGGERを作成します :

    CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
    FOR INSERT ON CONTRACTS
    COMPOUND TRIGGER
      V_CLIENTS NUMBER_LIST;
    
      BEFORE STATEMENT
        IS
      BEGIN
        V_CLIENTS:= NUMBER_LIST();
      END BEFORE STATEMENT;
    
      AFTER EACH ROW
        IS
      BEGIN
        V_CLIENTS.EXTEND();
        V_CLIENTS(V_CLIENTS.COUNT) := :NEW.CLIENTID;
      END AFTER EACH ROW;
    
      AFTER STATEMENT IS
      BEGIN
    
        MERGE INTO CONTRACTS
        USING (
                SELECT CONTRACTID,
                  CANDIDATE_ENDDATE AS ENDDATE
                FROM
                  (SELECT CONTRACTS.CONTRACTID,
                     (TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
                     DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
                   FROM CONTRACTS
                   WHERE CONTRACTS.CLIENTID IN (SELECT * FROM TABLE(V_CLIENTS)))
                WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
        ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
        WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
          WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
      END AFTER STATEMENT;
    
    END CONTRACT_ENDDATE_ADJUSTER;
    /
    

    上記の挿入を繰り返した後、結果は同じです:

    CONTRACTID  CLIENTID  STARTDATE  ENDDATE    
    Break-Ring  1         11-MAY-56  18-FEB-57  
    GoBackHome  1         19-FEB-57  02-MAY-57  
    Gardening   1         03-MAY-57             
    SaveGalaxy  2         15-JUN-77  14-NOV-80  
    DefendHoth  2         15-NOV-80  08-MAR-83  
    GoWedding   2         09-MAR-83             
    



    1. Innodb:複数の列をクエリしたときに、列リストに一致するFULLTEXTインデックスが見つかりません

    2. SQL Server SELECTLASTN行

    3. ユニオンクエリを使用したドロップダウン

    4. Dockerコンテナ内で実行されているPostgreSQLを監視する方法:パート1