2017-01-24 30 views
1

上記のように。 私は3つのテーブルがあると仮定します。DB2 SQL複数のトリガーカスケード

--table A, B, C 

とカスケードに意図されている2つのトリガー:

--trigger X, Y 
create trigger X 
after insert on A 
...(some codes) 
update B set ...(some codes); 

--and 
create trigger Y 
after update on B 
...(some codes) 
insert into C values (...(some codes)); 

--insert on A fire X to update B, then again fire Y to insert on C. 

しかし、問題は、第1のトリガXは問題なく解雇されたであるが、第2のトリガYがされていません最初の後に発砲。

上記のコードにはどのような問題がありますか?

私のプロジェクトでは、すべてのエンティティをテストするためのミニウェアハウスデータベースを作成しています。以下は私がこれまで行ってきたコードです。私はのためのSQLCODEとSQLSTATEのドキュメントを読んで

--TRIGGER-- 
------------------------------------------------------------------------------------------------------- 

--1)AUTO CREATE DELIVERY AFTER PLACING ORDER (no error) 
CREATE TRIGGER REQUEST_DELIVERY 
AFTER INSERT ON ORDER 
REFERENCING NEW AS N 
for each row mode db2sql 
INSERT INTO DELIVERY VALUES (
    DEFAULT, 
    N.ORDER_ID, 
    NULL 
)@ 

--2)UPDATE STOCK QTY AFTER ISSUED A SUCCESSFUL DELIVERY (UPDATE DELIVERY WITH COURIER_ID MEANS PARCEL HAS 
-- BEEN MAILED OUT) 
--(error here, sqlstate="21000" & "09000",for trigger "...UPDATELOG) 
drop trigger [email protected] 
CREATE TRIGGER UPDATESTOCK_STOCKOUT 
AFTER UPDATE OF COURIER_ID ON DELIVERY 
REFERENCING OLD AS O 
FOR EACH ROW MODE DB2SQL 
BEGIN 
    UPDATE STOCK 
    SET STOCK_QTY = STOCK_QTY - (SELECT ORDER_QTY FROM ORDER WHERE ORDER.ORDER_ID = O.ORDER_ID) 
    WHERE STOCK_ID IN (SELECT STOCK_ID FROM ORDER WHERE ORDER.ORDER_ID = O.ORDER_ID); 
[email protected] 


--NOT WORKING EITHER FOR BELOW ALTERNATIVES-- 
---------------------------------------------------------------------------------------------- 
CREATE PROCEDURE UPDATEDELIVERY(IN ORD_ID DECIMAL(11,0), COU_ID DECIMAL(3,0)) 
BEGIN 
    UPDATE DELIVERY SET COURIER_ID = COU_ID WHERE ORDER_ID = ORD_ID; 
    --UPDATE STOCK SET STOCK_QTY = STOCK_QTY - (SELECT ORDER_QTY FROM ORDER WHERE ORDER.ORDER_ID = ORD_ID); 
[email protected] 

DROP PROCEDURE [email protected] 
CREATE PROCEDURE UPDATEDELIVERY2(IN DLV_ID DECIMAL(11,0), COU_ID DECIMAL(3,0)) 
BEGIN 
    UPDATE DELIVERY SET COURIER_ID = COU_ID WHERE DELIVERY_ID = DLV_ID; 
    --UPDATE STOCK SET STOCK_QTY = STOCK_QTY - (SELECT ORDER_QTY FROM ORDER WHERE ORDER.ORDER_ID = (SELECT ORDER_ID FROM DELIVERY D WHERE D.DELIVERY_ID = DLV_ID)) 
    --WHERE STOCK_ID = (SELECT STOCK_ID FROM ORDER O, DELIVERY D WHERE D.DELIVERY_ID = DLV_ID AND D.ORDER_ID = O.ORDER_ID); 
[email protected] 

--------------------------------------------------------------------------------------------- 

--3)auto update delivery.COURIER_ID once stock out in log 
--(error here, sqlstate="21000" & "09000",for trigger "...UPDATELOG) 
drop trigger [email protected] 
CREATE TRIGGER UPDATELOG 
AFTER UPDATE OF STOCK_QTY ON STOCK 
REFERENCING OLD AS O 
FOR EACH ROW MODE DB2SQL 
BEGIN 
    IF O.STOCK_QTY < (SELECT STOCK_QTY FROM STOCK WHERE STOCK_ID = O.STOCK_ID) THEN 
     --STOCKIN 
     INSERT INTO LOG VALUES (
      GENERATE_UNIQUE(), 
      'Stock-in', 
      ((SELECT STOCK_QTY FROM STOCK WHERE STOCK_ID = O.STOCK_ID) - O.STOCK_QTY), 
      CURRENT DATE, 
      NULL, 
      O.STOCK_ID 
     ); 
     --UPDATE STOCK 
     --SET STOCK_QTY = STOCK_QTY - (SELECT ORDER_QTY FROM ORDER WHERE ORDER.ORDER_ID = O.ORDER_ID AND ORDER.STOCK_ID = STOCK.STOCK_ID); 
    ELSEIF O.STOCK_QTY > (SELECT STOCK_QTY FROM STOCK WHERE STOCK_ID = O.STOCK_ID) THEN 
     --STOCKOUT 
     INSERT INTO LOG VALUES (
      GENERATE_UNIQUE(), 
      'Stock-out', 
      (O.STOCK_QTY - (SELECT STOCK_QTY FROM STOCK WHERE STOCK_ID = O.STOCK_ID)), 
      CURRENT DATE, 
      (SELECT DELIVERY_ID FROM DELIVERY D, ORDER WHERE D.ORDER_ID = ORDER.ORDER_ID AND ORDER.STOCK_ID = O.STOCK_ID), 
      O.STOCK_ID 
     ); 
     END IF; 
[email protected] 

カスケード層のために正しい順序で、

--INSERT INTO TABLE-- 
INSERT INTO VENUE VALUES (111,1,1)@ 
INSERT INTO VENUE VALUES (112,2,2)@ 
INSERT INTO VENUE VALUES (113,3,3)@ 

INSERT INTO CLIENT VALUES (DEFAULT,'ROAN','CHENG','60189774541','28 JLN APA')@ 
INSERT INTO CLIENT VALUES (DEFAULT,'AAA','ABC','601','29 JLJ AAA')@ 
INSERT INTO CLIENT VALUES (DEFAULT,'BBB','BBC','60111234567','30 JLN BBB')@ 

INSERT INTO COURIER VALUES (100,'DHL','EXP','60355006666')@ 
INSERT INTO COURIER VALUES (200,'ABX','EXP','60344007777')@ 
INSERT INTO COURIER VALUES (300,'POS','LAJU','61300882525')@ 

INSERT INTO STOCK VALUES (DEFAULT,'IPHONE 7','APPLE',100,111)@ 
INSERT INTO STOCK (STOCK_ID,STOCK_NAME,SUPPLIER_NAME,VENUE_ID) VALUES (10000001,'SAMSUNG S7','SAMSUNG',112)@ 
INSERT INTO STOCK VALUES (DEFAULT,'MMU','TM',300,113)@ 
INSERT INTO STOCK VALUES (DEFAULT,'CINEMA','TGV',200,111)@ 
INSERT INTO STOCK VALUES (DEFAULT,'FOO','FOOCORP',1000,113)@ 

INSERT INTO ORDER VALUES (DEFAULT,10,10000,10000003)@ 
INSERT INTO ORDER VALUES (DEFAULT,20,10000,10000002)@ 
INSERT INTO ORDER VALUES (DEFAULT,30,10002,10000002)@ 

とトリガー部:

--create tables, no error over here i assumed 
CREATE TABLE VENUE(
VENUE_ID  DECIMAL(3,0) NOT NULL CHECK (VENUE_ID BETWEEN 111 AND 333), 
VENUE_FLOOR  INT NOT NULL CHECK (VENUE_FLOOR IN (1,2,3)), 
VENUE_SECTION INT NOT NULL CHECK (VENUE_SECTION IN (1,2,3)), 
PRIMARY KEY (VENUE_ID) 
)@ 

CREATE TABLE CLIENT(
    CLIENT_ID  DECIMAL(5,0) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 10000 INCREMENT BY 1) CHECK (CLIENT_ID BETWEEN 10000 AND 99999), 
    CLIENT_FNAME VARCHAR(30) NOT NULL, 
    CLIENT_LNAME VARCHAR(30) NOT NULL, 
    CLIENT_PHONE VARCHAR(12) NOT NULL, 
    CLIENT_ADDRS VARCHAR(300) NOT NULL, 
    PRIMARY KEY (CLIENT_ID), 
    CONSTRAINT CLIENT_PHONE_UNQ UNIQUE (CLIENT_PHONE) 
)@ 

CREATE TABLE COURIER(
    COURIER_ID  DECIMAL(3,0) NOT NULL CHECK (COURIER_ID BETWEEN 100 AND 999), 
    COURIER_FNAME VARCHAR(30) NOT NULL, 
    COURIER_LNAME VARCHAR(30) NOT NULL, 
    COURIER_PHONE VARCHAR(12) NOT NULL, 
    PRIMARY KEY (COURIER_ID), 
    CONSTRAINT COURIER_PHONE_UNQ UNIQUE (COURIER_PHONE) 
)@ 

CREATE TABLE STOCK(
    STOCK_ID  DECIMAL(8,0) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 10000000 INCREMENT BY 1) CHECK (STOCK_ID BETWEEN 10000000 AND 19999999), 
    STOCK_NAME  VARCHAR(20) NOT NULL, 
    SUPPLIER_NAME VARCHAR(50) NOT NULL, 
    STOCK_QTY  INT NOT NULL DEFAULT 0, 
    VENUE_ID  DECIMAL(3,0) NOT NULL, 
    PRIMARY KEY (STOCK_ID), 
    FOREIGN KEY (VENUE_ID) REFERENCES VENUE ON DELETE no action, 
    CONSTRAINT STOCK_NAME_UNQ UNIQUE (STOCK_NAME), 
    CONSTRAINT SUPPLIER_NAME_UNQ UNIQUE (SUPPLIER_NAME) 
)@ 

--CREATE TRIGGER/PROCEDURE CHECK STOCK_QTY - ORDER_QUANTITY >= 100-- 
CREATE TABLE ORDER(
    ORDER_ID  DECIMAL(11,0) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 10000000000 INCREMENT BY 1) CHECK (ORDER_ID BETWEEN 10000000000 AND 99999999999), 
    ORDER_QTY  INT NOT NULL CHECK (ORDER_QTY BETWEEN 10 AND 999), 
    CLIENT_ID  DECIMAL(5,0) NOT NULL, 
    STOCK_ID  DECIMAL(8,0) NOT NULL, 
    PRIMARY KEY (ORDER_ID), 
    FOREIGN KEY (CLIENT_ID) REFERENCES CLIENT(CLIENT_ID) ON DELETE no action, 
    FOREIGN KEY (STOCK_ID) REFERENCES STOCK(STOCK_ID) ON DELETE no action 
)@ 

CREATE TABLE DELIVERY(
    DELIVERY_ID  DECIMAL(11,0) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 16900000000 INCREMENT BY 1) CHECK (DELIVERY_ID BETWEEN 16900000000 AND 16999999999), 
    ORDER_ID  DECIMAL(11,0) NOT NULL, 
    COURIER_ID  DECIMAL(3,0), 
    PRIMARY KEY(DELIVERY_ID), 
    FOREIGN KEY(ORDER_ID)REFERENCES ORDER(ORDER_ID) ON DELETE no action, 
    FOREIGN KEY(COURIER_ID)REFERENCES COURIER(COURIER_ID) ON DELETE no action, 
    CONSTRAINT ORDER_ID_DELI_UNQ UNIQUE (ORDER_ID) 
)@ 

--TO SELECT FOR LOG- USE SELECT TIMESTAMP(LOG_ID), ... FROM [email protected] 
CREATE TABLE LOG(
    LOG_ID   CHAR(13) NOT NULL FOR BIT DATA, 
    LOG_PROCESS  VARCHAR(9) NOT NULL CHECK (LOG_PROCESS IN ('Stock-in','Stock-out')), 
    LOG_QTY   INT NOT NULL CHECK(LOG_QTY BETWEEN 10 AND 999), 
    LOG_DATE  DATE NOT NULL, 
    DELIVERY_ID  DECIMAL(11,0), 
    STOCK_ID  DECIMAL(8,0) NOT NULL, 
    PRIMARY KEY(LOG_ID), 
    FOREIGN KEY(DELIVERY_ID)REFERENCES DELIVERY(DELIVERY_ID), 
    FOREIGN KEY(STOCK_ID)REFERENCES STOCK(STOCK_ID) 
    --CONSTRAINT DELIVERY_ID_LOG_UNQ UNIQUE (DELIVERY_ID) 
)@ 

テストにいくつかの値を挿入エラーは、エラーがトリガーと1つ以上の値を返すいくつかのselectステートメントであると言います。

しかし、トリガ内のすべてのselect文(サブクエリとクエリ)をテストすると、エラーなしで動作する1つの値しか返されません。

ERROR: 
An error occurred in a triggered SQL statement 
in trigger "PCNAME.UPDATELOG". 
Information returned for the error includes SQLCODE "-811", 
SQLSTATE "21000" and message token "", SQLSTATE "09000" 

PS:説明で正しいことを行うために私を案内する代わりに、私はちょうど簡単な答えを与えることによって、私を助けてください、私の脳は、このSQLトラフィックに捕まってしまいました。私がこのレッスンから何かを学ぶことができなければ、私は正式に運命に陥っています。

答えて

1

エラーメッセージは非常に明示的です。正しく言えば、SELECTステートメントは、通常は割り当てまたはスカラー比較で単一の値のみが予想されるコンテキストで複数の行を返すという文句を言います。また、問題がPCNAME.UPDATELOGという名前のトリガーで発生していることがわかります。

トリガーのソースを見ると、スカラーコンテキストで使用される5つの副選択を見ることができます。それらのうちの4つはSTOCKからSTOCK_IDで選択します。これは主キーであるため、定義によって1つの行のみを返します。したがって、これは残りの声明です:

SELECT DELIVERY_ID FROM DELIVERY D, ORDER 
    WHERE D.ORDER_ID = ORDER.ORDER_ID AND ORDER.STOCK_ID = O.STOCK_ID 

これは問題を引き起こす可能性があります。 ORDERDELIVERYORDER_IDで結合しているため、このクエリは特定の注文の配送数と同数の行を返します。

+0

これはコードの実際の問題かもしれませんが、私は最初に試してみる必要があります、ありがとうございます。ところで、カスケードするための3つのダミーテーブル(各テーブルに2つの列を持つA、B、C)と2つのトリガー(X、Y、X火Y)を作成しようとしました。しかし、それは私が期待している方法ではうまくいかない。 –

+0

これは私のコードではまさにエラーですので、もう一度ありがとうございます。一時的に一時テーブルtempを作成し、UPDATELOGトリガーで使用するDELIVERYテーブルの一意のORDER_IDを一時的に保存しました。 –

0

私はあなたの質問から右enverythingてしまった場合、私はわからないが、ここでいくつかの点が検討している:

  • あなたのトリガREQUEST_DELIVERYは、INSERTを実行します REQUEST_DELIVERYをUPDATESTOCK_STOCKOUT解雇することはありませんし、UPDATESTOCK_STOCKOUTは、更新を待っています
  • 複数の行が返された場合のエラーについては、1行だけが返されることを保証する必要があります。あなたは、単一のPK値にフィルタリングするか、最初の1行だけをフェッチするか、そのようなものを使うことができます。
+0

REQUEST_DELIVERYはUPDATESTOCK_STOCKOUTまたはUPDATELOGを起動しません。しかし、あなたが指摘した第2のポイントは、私が逃した問題かもしれません、ありがとうございます。 –