2017-09-14 38 views
0

我在數據庫中有兩個表,一個是PS_POST,一個是PS_STAR。oracle數據庫在級聯和觸發時遇到刪除錯誤

這裏是有DDL:

-------------------------------------------------------- 
-- DDL for Table PS_POST 
-------------------------------------------------------- 

    CREATE TABLE "C##STY"."PS_POST" 
    ( "POST_ID" NUMBER GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE , 
    "USER_ID" NUMBER, 
    "GROUP_ID" NUMBER DEFAULT 0, 
    "TIME" DATE, 
    "TITLE" VARCHAR2(200 BYTE) DEFAULT 'Default_title', 
    "STAR_NUMBER" NUMBER DEFAULT 0, 
    "CONTENT" VARCHAR2(4000 BYTE) DEFAULT 'Default_content' 
    ) ; 
-------------------------------------------------------- 
-- DDL for Index POST_PK 
-------------------------------------------------------- 

    CREATE UNIQUE INDEX "C##STY"."POST_PK" ON "C##STY"."PS_POST" ("POST_ID") ; 
-------------------------------------------------------- 
-- Constraints for Table PS_POST 
-------------------------------------------------------- 

    ALTER TABLE "C##STY"."PS_POST" MODIFY ("USER_ID" NOT NULL ENABLE); 
    ALTER TABLE "C##STY"."PS_POST" ADD CONSTRAINT "POST_PK" PRIMARY KEY ("POST_ID") 
    ENABLE; 
    ALTER TABLE "C##STY"."PS_POST" MODIFY ("POST_ID" NOT NULL ENABLE); 



-------------------------------------------------------- 
-- DDL for Table PS_STAR 
-------------------------------------------------------- 

    CREATE TABLE "C##STY"."PS_STAR" 
    ( "USER_ID" NUMBER, 
    "POST_ID" NUMBER, 
    "TIME" DATE 
    ) ; 
-------------------------------------------------------- 
-- DDL for Index STAR_PK 
-------------------------------------------------------- 

    CREATE UNIQUE INDEX "C##STY"."STAR_PK" ON "C##STY"."PS_STAR" ("USER_ID", "POST_ID") 
    ; 
-------------------------------------------------------- 
-- DDL for Trigger STAR_TRIGGER 
-------------------------------------------------------- 

    CREATE OR REPLACE EDITIONABLE TRIGGER "C##STY"."STAR_TRIGGER" after insert on PS_STAR 
referencing new as new old as old 
for each row 
begin 
update PS_POST 
set 
STAR_NUMBER = STAR_NUMBER + 1 
where POST_ID = :new.POST_ID; 

end; 
/
ALTER TRIGGER "C##STY"."STAR_TRIGGER" ENABLE; 
-------------------------------------------------------- 
-- DDL for Trigger STAR_DELETE_TRIGGER 
-------------------------------------------------------- 

    CREATE OR REPLACE EDITIONABLE TRIGGER "C##STY"."STAR_DELETE_TRIGGER" before delete on PS_STAR 
referencing new as new old as old 
for each row 
begin 
update PS_POST 
set 
STAR_NUMBER = STAR_NUMBER - 1 
where POST_ID = :old.POST_ID; 

end; 
/
ALTER TRIGGER "C##STY"."STAR_DELETE_TRIGGER" ENABLE; 
-------------------------------------------------------- 
-- Constraints for Table PS_STAR 
-------------------------------------------------------- 

    ALTER TABLE "C##STY"."PS_STAR" ADD CONSTRAINT "STAR_PK" PRIMARY KEY ("USER_ID", "POST_ID") 
    ENABLE; 
    ALTER TABLE "C##STY"."PS_STAR" MODIFY ("POST_ID" NOT NULL ENABLE); 
    ALTER TABLE "C##STY"."PS_STAR" MODIFY ("USER_ID" NOT NULL ENABLE); 

所以我設置PS_STAR當帖子被刪除被級聯刪除。我還有一個觸發器,用於在刪除星形記錄時更新PS_POST表中的STAR_NUMBER。當我嘗試刪除PS_POST中的某個項目時,似乎PS_STAR中的觸發器無法正常工作,並且出現錯誤:

ORA-04091: C##STY.PS_POST is mutating, trigger/function may not see it 

如何解決此問題?提前致謝。

+0

我將很多不相關的存儲子句等等從DDL中刪除掉了,所以我們可以更輕鬆地讀取它。現在看起來這裏根本就沒有外鍵定義 - 我回去檢查了一下,在我的編輯之前也沒有! –

回答

1

可能最好的方案是從PS_POST表中刪除非規範化的 STAR_NUMBER列,並刪除觸發器 - 只需要計算PS_STAR記錄的數量即可。除非在一些極端情況下,否則「表現非規範化」很少有理由。

但是,如果您確實需要保留它,則需要防止觸發器在從中刪除記錄時嘗試更新PS_POST表。這可以通過使用一個包在裏面,而實現與一個全局變量是這樣的:

create or replace package ps_post_pkg is 
    deleting_post boolean default false; 
end; 

然後添加兩個聲明 - 電平觸發到PS_POST:

create or replace trigger ps_post_before_delete_stmt 
before delete on ps_post 
begin 
    ps_post_pkg.deleting_post := true; 
end; 

create or replace trigger ps_post_after_delete_stmt 
after delete on ps_post 
begin 
    ps_post_pkg.deleting_post := false; 
end; 

現在修改你START_DELETE_TRIGGER的身體:

begin 
    if not ps_post_pkg.deleting_post then 
    update PS_POST 
    set STAR_NUMBER = STAR_NUMBER - 1 
    where POST_ID = :old.POST_ID; 
    end if; 
end; 

現在,當記錄從PO_POST中刪除時,刪除將級聯到PS_STAR,但START_DELETE_TRIGGER將n不要嘗試更新剛刪除的PS_POST記錄。