2015-04-04 56 views
1

我創建了一個觸發器,以便在插入或更新預訂記錄時,如果評估爲0,則將預訂的詳細信息插入到審計表中。下面的觸發器完美的作品,如果我更新記錄,但是在插入它給了我下面的錯誤:ORACLE SQL觸發器 - 未找到數據

INSERT INTO "SCOTT"."BOOKING" (PASSENGER_PASSENGER_ID, VOYAGE_VOYAGE_ID, CABIN_NUM, CLASS, EVALUATION) VALUES ('2', '1', '202', 'SECOND', '0') 
ORA-01403: no data found 
ORA-01403: no data found 
ORA-06512: at "SCOTT.EVALUATION_TRIG", line 8 
ORA-04088: error during execution of trigger 'SCOTT.EVALUATION_TRIG' 
ORA-06512: at line 1 


One error saving changes to table "SCOTT"."BOOKING": 
Row 2: ORA-01403: no data found 
ORA-01403: no data found 
ORA-06512: at "SCOTT.EVALUATION_TRIG", line 8 
ORA-04088: error during execution of trigger 'SCOTT.EVALUATION_TRIG' 
ORA-06512: at line 1 

Oracle的SQL觸發代碼:

create or replace trigger EVALUATION_TRIG 
AFTER INSERT OR UPDATE 
ON BOOKING 
FOR EACH ROW 
WHEN (NEW.EVALUATION =0) 
DECLARE 
PRAGMA AUTONOMOUS_TRANSACTION; 
PASSENGER_NAME VARCHAR2(30); 
CRUISE_NAME VARCHAR2(30); 
VOYAGE_DATE DATE; 
SHIP_NAME1 VARCHAR2(30); 
BEGIN 
SELECT NAME INTO PASSENGER_NAME FROM PASSENGER JOIN BOOKING 
ON PASSENGER.PASSENGER_ID = BOOKING.PASSENGER_PASSENGER_ID 
WHERE BOOKING.PASSENGER_PASSENGER_ID = :NEW.PASSENGER_PASSENGER_ID 
AND ROWNUM = 1; 
SELECT NAME INTO CRUISE_NAME FROM CRUISE JOIN VOYAGE 
ON CRUISE.CRUISE_ID = VOYAGE.CRUISE_CRUISE_ID 
JOIN BOOKING ON 
VOYAGE.VOYAGE_ID = BOOKING.VOYAGE_VOYAGE_ID 
WHERE BOOKING.VOYAGE_VOYAGE_ID = :NEW.VOYAGE_VOYAGE_ID 
AND ROWNUM= 1; 
SELECT START_DATE INTO VOYAGE_DATE FROM VOYAGE JOIN BOOKING 
ON VOYAGE.VOYAGE_ID= BOOKING.VOYAGE_VOYAGE_ID 
WHERE BOOKING.VOYAGE_VOYAGE_ID = :NEW.VOYAGE_VOYAGE_ID 
AND ROWNUM = 1; 
SELECT SHIP_NAME INTO SHIP_NAME1 FROM SHIP JOIN VOYAGE 
ON SHIP.SHIP_ID = VOYAGE.SHIP_SHIP_ID JOIN BOOKING 
ON VOYAGE.VOYAGE_ID= BOOKING.VOYAGE_VOYAGE_ID 
WHERE BOOKING.VOYAGE_VOYAGE_ID = :NEW.VOYAGE_VOYAGE_ID 
AND ROWNUM = 1; 
INSERT INTO EVALUATION_AUDIT VALUES (PASSENGER_NAME, CRUISE_NAME,VOYAGE_DATE, SHIP_NAME1,:NEW.EVALUATION); 
COMMIT; 
END; 
+0

你怎麼讀這樣一個龐大的代碼塊? – GolezTrol 2015-04-04 16:54:43

+0

我知道發佈大型代碼並不理想,但由於顯而易見的原因,它是一個相當大的觸發器。 – user2838928 2015-04-04 16:58:07

+0

這不是因爲它很大,而是因爲它全部大寫,沒有空白,沒有評論,也沒有任何縮進。當然,你的選擇,但我個人覺得很難閱讀和調試。 – GolezTrol 2015-04-04 17:00:42

回答

2

當你執行一個select..into聲明出現該錯誤不會返回一行,例如觸發器中的第一個。

SELECT NAME INTO PASSENGER_NAME FROM PASSENGER JOIN BOOKING 
ON PASSENGER.PASSENGER_ID = BOOKING.PASSENGER_PASSENGER_ID 
WHERE BOOKING.PASSENGER_PASSENGER_ID = :NEW.PASSENGER_PASSENGER_ID 
AND ROWNUM = 1; 

這些新的值應填寫在刀片一樣好更新,但這並不意味着實際的數據同樣存在。

上面的查詢將在預訂時加入乘客,但是如果您爲該乘客插入第一個預訂,則不存在當前預訂。此外,要獲取乘客的姓名,根本不需要預訂。而且,在同一個表的行級觸發器上查詢表X可能會產生問題。

所以,長話短說,我覺得上面這句話應該是這樣的:

SELECT NAME INTO PASSENGER_NAME 
FROM PASSENGER 
WHERE PASSENGER.PASSENGER_ID = :NEW.PASSENGER_PASSENGER_ID; 

同樣的變化還需要其他的語句來進行。

之後,理論上你仍然會得到相同的錯誤,但只有在以下情況下:NEW.PASSENGER_PASSENGER_ID與任何乘客的ID不匹配。但是在那種情況下,我認爲如果你配置了這些約束,你應該首先得到一個外鍵約束錯誤。

我也看到在觸發器的末尾提交。這也沒有多大意義。觸發器是聲明的一部分,聲明本身應該是原子的。從觸發器提交,如果這可以工作,則會自動提交多行插入中的每一行。 Suggested reading material

+0

謝謝你的幫助,你的解釋非常清楚,我現在明白了原因。我改變了選擇到你的建議和觸發器現在完美。再次感謝 :) – user2838928 2015-04-04 17:11:56