約束5:外鍵約束


在關系型數據庫中,表與表之間存在引用關系,也就是說,數據列C1引用其他表的數據列C2中存在的值,引用關系通過外鍵(Foreign Key )約束實現。如果表(TableA)中的列C1被其他表引用,那么,我們把表(TableA)稱作參考表,或引用表(Referenced Table),該列C1是其他表的參考列,或引用列(Referenced Column),對引用列執行Update 或 Delete 操作會受到很多限制。某些情況下,也把參考表稱作父表,把引用父表的列稱作子列,或外鍵列。

[ FOREIGN KEY ]   
        REFERENCES [ schema_name . ] referenced_table_name [ ( ref_column ) ]   
        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]   
        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]   

例如,在數據列C1和C2之間創建外鍵約束,C1是引用列,C2列引用C1列的值,外鍵約束的特點:

  • 如果C2列的值不是NULL,那么C2列的值必須存在於C1列中,否則,系統返回違反外鍵約束的錯誤;
  • 外鍵約束可以創建在同一個表的不同列之間,這種引用類型稱作自引用;
  • 外鍵約束可以引用單列,也可以引用多列;
  • 外鍵約束只能引用那些構成主鍵或唯一約束的數據列,或者唯一索引鍵列,也就是說,外鍵約束的引用列(單列或復合列)必須是唯一的;

一,外鍵約束的級聯操作

當引用列的值被更新(UPDATE或DELETE)時,子列會采取相應的動作:

  • 默認行為是NO ACTION:如果子列引用父表的值,那么父表的更新操作被回滾,數據庫拋出錯誤;
  • 級聯操作(CASCADE):當父表刪除數據行A時,子表刪除引用該數據行A的所有行;當父表更新數據行B時,子表把引用該數據行B的所有數據行都更新為新值;
  • 置空(SET NULL):當父表更新數據行A時,子表把引用該數據行A的所有數據行都設置為NULL,該設置要求外鍵列必須可空(nullable);
  • 設置默認值(SET DEFAULT):當父表更新數據時,子表把引用該數據行的數據行都設置為外鍵列的默認值,該設置要求外鍵列必須有默認值定義,如果構成外鍵的某一個列,沒有顯式定義默認值,並且可為NULL,那么系統把NULL作為列的默認值。

這些級聯操作是系統預定義的,不能更改。

二,手動更新外鍵

在對引用列進行更新操作(Update 和 Delete)之前,必須禁用外鍵約束,然后手動更新,最后再次啟用外鍵約束。手動更新外鍵,給用戶提供了很大的靈活性,由用戶保證外鍵約束的有效性。

1,查看外鍵列的信息

使用 sys.foreign_keyssys.foreign_key_columns 這兩個系統表獲取外鍵約束的信息

select fk.object_id as FK_Object_ID,
    fk.name as FK_name,
    pt.name as ParentTable_Name,
    pc.name as ParentTable_Column_Name,
    rt.name as ReferencedTable_Name,
    rc.name as ReferencedTable_Column_Name
from sys.foreign_keys fk with(nolock)
inner join sys.foreign_key_columns fkc with(nolock)
    on fk.object_id=fkc.constraint_object_id
inner join sys.tables pt with(nolock)
    on fkc.parent_object_id=pt.object_id
inner join sys.columns pc with(nolock)
    on fkc.parent_object_id=pc.object_id 
        and fkc.parent_column_id=pc.column_id
inner join sys.tables as rt with(nolock)
    on fkc.referenced_object_id=rt.object_id
inner join sys.columns rc with(nolock)
    on fkc.referenced_object_id=rc.object_id 
        and fkc.referenced_column_id=rc.column_id
where rt.name=N'Referenced_Table_name
View Code

2,禁用外鍵列

--disable FK constraint
alter table ParentTable_name
nocheck constraint FK_name

將外鍵 nocheck之后,可以使用 Delete 或 Update 命令更新數據,但是,當使用 Truncate 命令時,依然會報錯

Cannot truncate table 'xxx' because it is being referenced by a FOREIGN KEY constraint.

3,啟用外鍵列

--enable FK constraint
alter table ParentTable_name
check constraint FK_name

三,擴展引用完整性

系統自定義的外鍵約束,由很多限制,例如,引用列和外鍵列必須在相同的服務器上,相同的數據庫中,不支持跨數據庫的外鍵約束。而外鍵約束,實際上,就是一列引用另外一列的值,這個功能可以由觸發器來實現,用於擴展引用完整性。觸發器的實現過程是:創建INSTEAD OF觸發器,在插入數據之前,檢查插入的數據是否存在於參考表中,如果存在,插入成功;如果不存在,回滾事務,拋出異常。

CREATE TRIGGER schema_name.trigger_name   
ON table_name
INSTEAD OF { [ INSERT ] [ , ] [ UPDATE ] }   
AS { sql_statement  [ ; ] [ ,...n ] } 

在DML觸發器中,有兩個特殊的系統表inserted和deleted,用於表示插入的新數據和刪除的舊數據。

 

參考文檔:

Use the inserted and deleted Tables

How can I list all foreign keys referencing a given table in SQL Server?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM