ORACLE SQL 触发器中的更新语句在 2 行后不起作用
ORACLE SQL UPDATE STATEMENT IN TRIGGER NOT WORKING AFTER 2 ROWS
CREATE OR REPLACE TRIGGER BILL_TRG
BEFORE INSERT ON bill
FOR EACH ROW
DECLARE
d_id VARCHAR2(20);
doc_id VARCHAR2(20);
R_ID VARCHAR2(20);
p_name varchar2(20);
BEGIN
IF :NEW.BILL_NO IS NULL THEN
SELECT BILL_NO_SEQ.NEXTVAL INTO :NEW.BILL_NO FROM DUAL;
END IF;
IF :NEW.BILL_DATE IS NULL THEN
UPDATE BILL set BILL_DATE=TO_CHAR(SYSDATE);
END IF;
IF :NEW.p_name IS NULL THEN
SELECT p_name INTO :NEW.P_NAME FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.P_GENDER IS NULL THEN
SELECT P_GENDER INTO :NEW.P_GENDER FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.P_ADDRESS IS NULL THEN
SELECT P_ADDRESS INTO :NEW.P_ADDRESS FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.D_NAME IS NULL THEN
SELECT D_ID INTO DOC_ID FROM PATIENT WHERE P_ID=:NEW.P_ID;
SELECT D_NAME INTO :NEW.D_NAME FROM DOCTOR WHERE D_ID = DOC_ID;
END IF;
IF :NEW.DATE_ADMISSION IS NULL THEN
SELECT DATE_ADMISSION INTO :NEW.DATE_ADMISSION FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.days_admitted IS NULL THEN
UPDATE BILL SET DAYS_ADMITTED=abs(to_date(date_admission)-to_date(date_discharge));
END IF;
IF :NEW.room_charges IS NULL THEN
SELECT room_id INTO R_ID FROM PATIENT WHERE P_ID=:NEW.P_ID;
SELECT room_charges INTO :NEW.room_charges FROM room WHERE room_id=R_ID;
UPDATE BILL SET ROOM_CHARGES=ROOM_CHARGES*DAYS_ADMITTED;
END IF;
IF :NEW.total_amount IS NULL THEN
UPDATE BILL SET TOTAL_AMOUNT=ROOM_CHARGES+PATHOLOGY_FEES+D_FEES+MISCELLANEOUS;
END IF;
END;
/
首先,我使用的是 Oracle SQL Developer。
在这个触发器中,我使用了三个更新语句....它们在两行之前工作正常,之后....值仅变为空值。
谁能帮我解决这个问题?
This update statement is working till 2 rows only.....after that it is not working.....I am attaching a screenshot of one of the columns.
Attaching 2nd picture here
为什么使用update
而不是直接赋值?您无法更新尚未插入的行,因此您输入的最后一行将始终不正确,并且您将无缘无故地更新 table 中的所有其他行。
总体而言,您的代码和数据模型似乎有 数量 个重大问题:
- 您正在将日期存储为文本
- 当直接分配(例如
NEW.BILL_NO := NVL(:NEW.BILL_NO,BILL_NO_SEQ.NEXTVAL);
)可行时,您正在 使用 select into
- 您 避免使用 SQL 联接 而您应该使用它们来
减少 SQL 执行次数(例如
SELECT D_NAME INTO :NEW.D_NAME FROM DOCTOR D, PATIENT P WHERE D.D_ID = P.D_ID AND P.P_ID = :NEW.P_ID;
)
- 您正在 使用
update
修改相同 table 的 所有行
调用触发器 除了 实际插入的行
- 没有格式验证 to_date 或 to_char 过滤器(如果您实际存储的是日期而不是文本,则不需要)
- 你使用了一个不必要的函数调用 abs 而你可以简单地反转
两个日期的顺序
CREATE OR REPLACE TRIGGER BILL_TRG
BEFORE INSERT ON bill
FOR EACH ROW
DECLARE
d_id VARCHAR2(20);
doc_id VARCHAR2(20);
R_ID VARCHAR2(20);
p_name varchar2(20);
BEGIN
IF :NEW.BILL_NO IS NULL THEN
SELECT BILL_NO_SEQ.NEXTVAL INTO :NEW.BILL_NO FROM DUAL;
END IF;
IF :NEW.BILL_DATE IS NULL THEN
UPDATE BILL set BILL_DATE=TO_CHAR(SYSDATE);
END IF;
IF :NEW.p_name IS NULL THEN
SELECT p_name INTO :NEW.P_NAME FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.P_GENDER IS NULL THEN
SELECT P_GENDER INTO :NEW.P_GENDER FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.P_ADDRESS IS NULL THEN
SELECT P_ADDRESS INTO :NEW.P_ADDRESS FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.D_NAME IS NULL THEN
SELECT D_ID INTO DOC_ID FROM PATIENT WHERE P_ID=:NEW.P_ID;
SELECT D_NAME INTO :NEW.D_NAME FROM DOCTOR WHERE D_ID = DOC_ID;
END IF;
IF :NEW.DATE_ADMISSION IS NULL THEN
SELECT DATE_ADMISSION INTO :NEW.DATE_ADMISSION FROM PATIENT WHERE P_ID=:NEW.P_ID;
END IF;
IF :NEW.days_admitted IS NULL THEN
UPDATE BILL SET DAYS_ADMITTED=abs(to_date(date_admission)-to_date(date_discharge));
END IF;
IF :NEW.room_charges IS NULL THEN
SELECT room_id INTO R_ID FROM PATIENT WHERE P_ID=:NEW.P_ID;
SELECT room_charges INTO :NEW.room_charges FROM room WHERE room_id=R_ID;
UPDATE BILL SET ROOM_CHARGES=ROOM_CHARGES*DAYS_ADMITTED;
END IF;
IF :NEW.total_amount IS NULL THEN
UPDATE BILL SET TOTAL_AMOUNT=ROOM_CHARGES+PATHOLOGY_FEES+D_FEES+MISCELLANEOUS;
END IF;
END;
/
首先,我使用的是 Oracle SQL Developer。 在这个触发器中,我使用了三个更新语句....它们在两行之前工作正常,之后....值仅变为空值。
谁能帮我解决这个问题?
This update statement is working till 2 rows only.....after that it is not working.....I am attaching a screenshot of one of the columns.
Attaching 2nd picture here
为什么使用update
而不是直接赋值?您无法更新尚未插入的行,因此您输入的最后一行将始终不正确,并且您将无缘无故地更新 table 中的所有其他行。
总体而言,您的代码和数据模型似乎有 数量 个重大问题:
- 您正在将日期存储为文本
- 当直接分配(例如
NEW.BILL_NO := NVL(:NEW.BILL_NO,BILL_NO_SEQ.NEXTVAL);
)可行时,您正在 使用select into
- 您 避免使用 SQL 联接 而您应该使用它们来
减少 SQL 执行次数(例如
SELECT D_NAME INTO :NEW.D_NAME FROM DOCTOR D, PATIENT P WHERE D.D_ID = P.D_ID AND P.P_ID = :NEW.P_ID;
) - 您正在 使用
update
修改相同 table 的 所有行 调用触发器 除了 实际插入的行 - 没有格式验证 to_date 或 to_char 过滤器(如果您实际存储的是日期而不是文本,则不需要)
- 你使用了一个不必要的函数调用 abs 而你可以简单地反转 两个日期的顺序