sql >> Databáze >  >> RDS >> Oracle

Jak implementovat tento trigger na Oracle SQL?

Souhlasím s uveřejněnými komentáři, že pomáhá mít některá specifika o tom, co selhává v předchozích pokusech, a také bych doporučil nepoužívat TRIGGER vůbec pro tento druh věcí.
Ale protože se jedná o studijní cvičení, zde je několik příkladů, které by mohly být výchozím místem.

Upravil jsem vaše tabulky tak, aby nepovolovaly NULL PRIMARY KEY s v těchto příkladech.

Chcete-li začít, vytvořte tabulky:

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
);

Poté vytvořte prvního 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;

Poté vytvořte TRIGGER . V tomto prvním příkladu TRIGGER je AFTER STATEMENT typu.
Je to jednoduché, ale neefektivní, protože vyhodnocuje každý CLIENT po každém INSERT prohlášení.
Proti velkému souboru dat nebo tváří v tvář vícenásobnému TRIGGER s, to může být problém.
Tento TRIGGER zkontroluje předchozí smlouvu a nastaví její ENDDATE do jednoho dne před uzavřením nové smlouvy, pokud je neplatná, nebo po začátku nové smlouvy.

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;
  /

Pak to vyzkoušejte.
Přidejte počáteční smlouvy. Neočekávají se žádné změny koncového data, protože se jedná o první. Frodova smlouva zde má již stanovené datum ukončení.

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             

Pak přidejte nové smlouvy.
Frodova nová smlouva začíná před koncem jeho stávající smlouvy, takže datum ukončení bude upraveno.
Chewieho původní smlouva neměla KONCOVNÍ DATUM, takže bude také upravena.

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             

A jak se podepisují další smlouvy, vzorec pokračuje:

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             

Ke stabilizaci zátěže na tomto dotazu lze místo toho použít COMPOUND TRIGGER. Tento druhý příklad dosahuje stejného výsledku jako první, ale pouze dotazuje CONTRACT s CLIENT s, které se změnily:

Nejprve ROLLBACK; Poté vytvořte typ, který bude používat TRIGGER :

CREATE OR REPLACE TYPE NUMBER_LIST IS TABLE OF NUMBER;
/

Poté vytvořte 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;
/

Po zopakování výše uvedených vložek je výsledek stejný:

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. Počet MySQL ve stejné tabulce včetně nulových hodnot počtu

  2. JDBC - Statement, PreparedStatement, CallableStatement a ukládání do mezipaměti

  3. Mysql Vložit číslo objednávky podle pole VARCHAR

  4. Doporučené postupy pro práci s více tabulkami