2017-01-24 78 views
1

如上述標題所述。 假設我有3張桌子。DB2 SQL多級觸發器級聯

--table A, B, C 

和兩個觸發器,旨在級聯:

--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. 

但問題是第一個觸發X而沒有問題,但第二個觸發Y被不被解僱第一次發射後。

上述代碼可能存在什麼問題?

對於我的項目,我創建了一個微型倉庫數據庫來測試所有實體。以下是我迄今爲止所做的代碼。

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

插入一些值測試:

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

和觸發部,以正確的順序級聯層

--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] 

我讀SQLCODE和SQLSTATE的文檔錯誤,並且它說錯誤與觸發器和一些返回多個值的select語句有關。

但是,當測試觸發器中的所有select語句(子查詢和查詢)時,它全部只返回1個值,該值無誤地工作。 PS:請幫助我指導我做解釋正確的事情,而不是給我直接的答案,我的大腦陷入了這種SQL流量。如果我無法從這節課中學到任何東西,那麼我就正式註定了。

回答

1

好吧,錯誤信息是非常明確的:正如你所說的,它抱怨在預期只有單個值的上下文中返回多於一行的語句(通常在賦值或標量比較中)。它還會告訴您,該問題發生在名爲PCNAME.UPDATELOG的觸發器中。

查看該觸發器的源代碼,可以看到標量上下文中使用了5個子查詢語句。其中四個從STOCK中選擇STOCK_ID,這是主鍵,因此按照定義只返回一行。因此,這是其餘的聲明:

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

這可能會導致問題。由於您正在加入ORDERDELIVERY,ORDER_ID,因此此查詢將返回與特定訂單的交貨數量一樣多的行。

+0

這可能是代碼真正的問題,我必須先嚐試一下,謝謝。順便說一下,我試着創建3個虛擬表(每個表中有兩列的A,B,C)和2個旨在級聯的觸發器(X,Y和X fire Y)。但它並不按我期望的方式工作。 –

+0

再次感謝你,因爲那正是我的代碼中的錯誤,現在我創建了一個臨時表temp,在此臨時存儲DELIVERY表中的唯一ORDER_ID以用於UPDATELOG觸發器。 –

0

我不知道,如果我得到的權利從你的問題enverything但這裏有一些需要考慮的要點:

  • 你觸發REQUEST_DELIVERY將永遠不會觸發UPDATESTOCK_STOCKOUT REQUEST_DELIVERY將執行INSERT和UPDATESTOCK_STOCKOUT正在等待更新
  • 關於多行返回的錯誤 - 您必須保證只返回一行。你可以嘗試過濾到一個單一的PK值或只使用第一行獲取或類似的東西。
+0

REQUEST_DELIVERY不會觸發UPDATESTOCK_STOCKOUT或UPDATELOG。但對於你指出的第二點可能是我錯過的問題,謝謝。 –