2013-07-12 38 views
-2

我需要定義一個觸發器,我想申請一列的表。觸發器應限制用戶輸入重複值和非空值。或者你可以說,我需要知道主鍵的邏輯。如何使主鍵約束成爲觸發器?

+2

你可以簡單地定義列是'unique'和'不空'' – NINCOMPOOP

+0

是的,我知道我可以,但我想學習,主鍵是如何作出的(當然這是一個觸發器)我想使自己的觸發器應該與主鍵相同 –

+0

爲什麼你認爲主鍵是作爲觸發器實現的嗎?約束和觸發器是完全不同的東西 –

回答

1

主鍵不是觸發器。這是一個關鍵,因爲它標識了整個行,​​這就是爲什麼它應該是唯一的(並且隱含地不爲空)。它是「主要」的,因爲它是最適合的候選關鍵 - 通過您的決定 - 成爲您桌子的主要參考關鍵。您可以將其添加爲ALTER TABLE your_table_name ADD CONSTRAINT PK_your_table_name PRIMARY KEY (your_key_column)

如果您不想添加這樣的主鍵(這是一個壞主意),但想要爲該表添加唯一索引:CREATE UNIQUE INDEX UQ_IX_your_table_your_column ON your_table_name (unique_column_name)NOT NULL約束應該放在列上。

+0

是的,只是主鍵是最適合(通過您的決定)成爲主要參考的候選鍵ce鍵爲您的桌子。我應該把這個放在我的答案中,對不起。 – Koshinae

+0

感謝您的領導! – Koshinae

+0

你會完全錯誤的方式! 我不問,如何定義鍵和它們的用法。 –

2

「我想學習,關鍵是如何主要是由(這是當然的觸發)」

有「當然」沒有這件事。約束不是觸發器。這是一個內部流程,它使用索引和許多低級活動來以可靠和高效的方式強制執行關係約束。

如果你想了解規則是非常簡單的:非空,唯一性,序列化。所以試着在觸發器中實現一個主鍵。你會發現你不能(擾亂警報!)因爲「變異表」的問題。如果你不明白這意味着什麼,那麼有一個很好的主題需要閱讀。


有一個問題:「是不是可以定義一個觸發器,它在插入之前 檢查的價值,它不應該是零和 獨特性呢?」

的回答這個問題是,不,你可以編寫一個基於觸發器的實現,但像其他「變異表」變通方法一樣,它需要一個包和AFTER語句觸發器(所以在技術上不需要插入之前)。

但是嚴重的是,會有什麼意義呢?你不會學到關於主鍵實際工作的任何信息。變異表幾乎總是指向一個糟糕的數據模型,這當然就是這種情況。

+0

謝謝APC。我清楚這不是一個觸發器。是的,會有一個變化的條件。 有一個問題:「是不是可以定義一個觸發器,它在插入之前檢查值,它不應該是空的且唯一嗎?」 –

2

僅僅因爲你似乎就看到了這個失敗,並且不採取任何從APC的分離開的意圖,這似乎只要它是一個before觸發乍一看工作:

create table t42 (id number); 

create trigger trig42 
before insert or update on t42 
for each row 
declare 
    c number; 
begin 
    if :new.id is null then 
    raise_application_error(-20001, 'ID is null');  
    end if; 
    select count(*) into c from t42 where id = :new.id; 
    if c > 0 then 
    raise_application_error(-20002, 'ID is not unique'); 
    end if; 
end; 
/

它編譯,如果你插入數據,你會得到你似乎想要的行爲:

insert into t42 values (1); 

1 rows inserted. 

insert into t42 values (1); 

Error starting at line 20 in command: 
insert into t42 values (1) 
Error report: 
SQL Error: ORA-20002: ID is not unique 
ORA-06512: at "STACKOVERFLOW.TRIG42", line 9 
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42' 

insert into t42 values (null); 

Error starting at line 22 in command: 
insert into t42 values (null) 
Error report: 
SQL Error: ORA-20001: ID is null 
ORA-06512: at "STACKOVERFLOW.TRIG42", line 5 
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42' 

select * from t42; 

     ID 
---------- 
     1 

這似乎是做你想做的。但是,如果您有多個會話,則不能。我在這次會議上沒有犯過;在另一個會話中,我可以這樣做:

insert into t42 values (1); 

1 row created. 

select * from t42; 

     ID 
---------- 
     1 

1 row selected. 

嗯,這很奇怪。那麼,也許這是推遲...讓我們犯他們倆:

commit; 

select * from t42; 
     ID 
---------- 
     1 
     1 

2 rows selected. 

糟糕。一旦會話無法看到另一個會話的未提交數據,那麼這將無法工作。

而且,變異表的問題表現出本身,當我們插入一條語句多行:

SQL> insert into t42 select level+1 from dual connect by level <= 5; 
insert into t42 select level+1 from dual connect by level <= 5 
      * 
ERROR at line 1: 
ORA-04091: table STACKOVERFLOW.T42 is mutating, trigger/function may not see it 
ORA-06512: at "STACKOVERFLOW.TRIG42", line 7 
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42' 


SQL> 

雙哎呀。

即使使用after觸發器和一個包來解決變異表問題,您仍然會遇到這個問題(我認爲),除非您爲每次插入或更新鎖定整個表。正如APC所說,這個約束是在數據庫的深處實施的,而不是在這個層面。

是不是可以定義一個觸發器,該觸發器檢查插入之前的值,它不應該是null也是唯一的?

不是當你有多個會話,沒有。即使在一次會議中,除非您在該列上有索引,否則性能不會隨着count(*)逐漸變慢而縮放。如果你確實有索引,那麼爲什麼不把它作爲唯一索引呢?

最後,從trigger design guidelines

不要創建重複的數據庫功能的觸發器。

例如,不要創建觸發器來拒絕無效數據,如果你能 做同樣的約束條件(見「How Triggers and Constraints Differ")。

+0

我很驚訝這個觸發器編譯和執行(特別是「執行「部分)。鑑於它似乎是一個行的觸發器,它在它所定義的表上做了一個SELECT操作,我預料它會得到一個「變異表」的錯誤。我在這裏錯過了什麼? –

+0

@Bob - 我也很驚訝,但我非常避免觸發器,我不確定觸發器是否僅影響觸發器 - 不這麼認爲。也許桌子是空的有所作爲 - 但它不知道呢?如果我記得我會在下週嘗試調查。 –

+0

非常感謝Alex。你已經很好地詳細解釋了。 非常感謝 –