我正在嘗試使用 Pre-Join 非規范化對這兩個表進行非規范化,并且必須添加所有需要的觸發器。
這些表看起來基本上是這樣的:
CLIENTS
Client_ID CHAR(13),
Client_Name VARCHAR2(20),
Client_Surname VARCHAR2 (30),
...
PRIMARY KEY (Client_ID)
ACCOUNTS
Account_ID VARCHAR(20),
...
Client_ID CHAR(13),
Client_Name VARCHAR2(20),
Client_Surname VARCHAR2(30),
PRIMARY KEY (ACCOUNT_ID),
FOREIGN KEY (Client_ID) REFERENCES CLIENTS(Client_ID)
我有兩個與我的問題相關的觸發器;一個用于禁用 Client_Name 和 Client_Surname 的手動編輯,如下所示:
CREATE OR REPLACE TRIGGER ACCOUNTS_NAME_SURNAME_UPDATE_DISABLE
BEFORE UPDATE OF CLIENT_NAME, CLIENT_SURNAME ON ACCOUNTS
FOR EACH ROW
BEGIN
RAISE_APPLICATION_ERROR( NUM => -20002, MSG => 'Updating client_name and client_surname is not permitted!');
END;
第二個觸發器用于在添加新帳戶時自動插入客戶姓名和姓氏,即連接到客戶。它看起來像這樣:
CREATE OR REPLACE TRIGGER ACCOUNTS_INSERT_UPDATE
BEFORE INSERT OR UPDATE ON ACCOUNTS
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
new_name VARCHAR2(20);
new_surname VARCHAR2(30);
BEGIN
EXECUTE IMMEDIATE 'ALTER TRIGGER ACCOUNTS_NAME_SURNAME_UPDATE_DISABLE DISABLE';
INSERT Client_Name INTO new_name FROM CLIENTS
WHERE Client_ID = :NEW.Client_ID;
:NEW.Client_Name := new_name;
INSERT Client_Surname INTO new_surname FROM CLIENTS
WHERE Client_ID = :NEW.Client_ID;
:NEW.Client_Surname := new_surname;
EXECUTE IMMEDIATE 'ALTER TRIGGER ACCOUNTS_NAME_SURNAME_UPDATE_DISABLE ENABLE';
END;
它有效!只要我洗掉 Execute immediate statements 和 pragma自治事務(并手動禁用第一個觸發器)。它達到了預期的效果 - 它使用客戶的姓名和姓氏填充行。
但是,當我添加編譯指示自主事務并執行即時陳述句時,Apex Oracle(SQL 命令)頁面凍結,然后崩潰,我必須重新加載頁面。
使用觸發器來實作此效果是一項要求,盡管它看起來確實不適合這項作業。
在撰寫此問題時,我正在使用最新版本的 Oracle Apex,即 Oracle APEX 22.1.0-17。
我會感謝任何人幫助解決這個爛攤子。提前致謝!
uj5u.com熱心網友回復:
兩個行級觸發器都BEFORE UPDATE在accounts表上觸發。好像 Oracle 無法決定它并試圖禁用一個觸發器,該觸發器剛剛觸發以通知您您正在嘗試做一些您不應該做的事情,并且 - 有點 - 最終陷入無限回圈。
那么,哪個觸發器將首先運行?據我所知,Oracle 沒有指定它,但讓您follows使用and來決定它precedes。像這樣的東西:
CREATE OR REPLACE TRIGGER accounts_name_surname_update_disable
BEFORE UPDATE OF client_name, client_surname
ON accounts
FOR EACH ROW
FOLLOWS accounts_insert_update --> this
BEGIN
raise_application_error (
num => -20002,
msg => 'Updating client_name and client_surname is not permitted!');
END;
此觸發器可以簡化(順便說一句,您發布的代碼似乎無效;沒有這樣的INSERT宣告 - 應該是SELECT):
CREATE OR REPLACE TRIGGER accounts_insert_update
BEFORE INSERT OR UPDATE
ON accounts
FOR EACH ROW
PRECEDES accounts_name_surname_update_disable --> this
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'ALTER TRIGGER ACCOUNTS_NAME_SURNAME_UPDATE_DISABLE DISABLE';
SELECT client_name, client_surname
INTO :new.client_name, :new.client_surname
FROM clients
WHERE client_id = :new.client_id;
EXECUTE IMMEDIATE 'ALTER TRIGGER ACCOUNTS_NAME_SURNAME_UPDATE_DISABLE ENABLE';
END;
另一方面——即使這樣可行——整個程序在我看來是錯誤的。觸發器如何accounts_name_surname_update_disable知道它應該(或不應該)觸發并允許對這兩列進行更改?對我來說,只有一個觸發器就足夠了 - 第二個(但已修改)。
所以:放下觸發器accounts_name_surname_update_disable,因為它沒用。
重新創建第二個觸發器:不需要禁用/啟用任何東西,因為另一個觸發器不再存在。始終從以下位置獲取客戶端名稱(因此,有人可能鍵入clients這些值并不重要- 觸發器將覆寫它們):
CREATE OR REPLACE TRIGGER accounts_insert_update
BEFORE INSERT OR UPDATE
ON accounts
FOR EACH ROW
BEGIN
SELECT client_name, client_surname
INTO :new.client_name, :new.client_surname
FROM clients
WHERE client_id = :new.client_id;
END;
最后,僅此而已?我不這么認為。整個資料模型是錯誤的。 ACCOUNTS表應該只 CLIENT_ID包含作為外鍵的列,查看CLIENTS.CLIENT_ID:
create table clients
(client_id number primary key,
client_name varchar2(20) not null,
client_surname varchar2(20) not null
);
create table accounts
(account_id number primary key,
client_id number constraint fk_acc_cli references clients (client_id)
);
因此,當accounts需要知道客戶端的名稱時,查詢將執行連接并獲取該資料:
select a.account_id, c.client_name
from accounts a join clients c on c.client_id = a.client_id
where a.account_id = 1234;
那應該可以解決您的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/467505.html
