天天看點

SQL Server中有關限制(constraint)的一些細節

原文:

SQL Server中有關限制(constraint)的一些細節

本文出處:

http://www.cnblogs.com/wy123/p/7350265.html

(保留出處并非什麼原創作品權利,本人拙作還遠遠達不到,僅僅是為了連結到原文,因為後續對可能存在的一些錯誤進行修正或補充,無他)

SQL Server 資料庫中的限制(Constrint)是作用是為了保證資料庫的完整性和一緻性,可以建表的時候指定某個字段要符合某種限制(或者對已有表的字段添加限制),比如唯一性(或者主鍵)限制,非空限制,預設值限制等

對于具體的限制,可以分為主鍵(唯一鍵)限制,預設值限制,檢查限制,外鍵限制等幾類。

限制的建立方式

  1,建表的時候指定

    如下,可以在建表的時候指定某些字段滿足某種限制。

SQL Server中有關限制(constraint)的一些細節

  2,以建立限制的方式指定

    也即在建表的時候沒有指定任何限制,在建表之後,以alter table的方式指定某些字段上的限制

    

SQL Server中有關限制(constraint)的一些細節

     

    對于Check或者Default限制,也可以事先定義出來規則(Rule),然後将規則綁定到對應表的字段

     如下分别定義了一個check限制和預設值限制,然後将表的字段綁定到對應的限制,這樣做的好處是對于某些複雜的限制,定義好限制之後就可以重用了

    需要注意的是,對于Rule來說,NULL值是不與任何規則沖突的,

    舉個例子,如下,雖然把TestConstrint.Sex字段指定了規則Rule_Sex,如果Sex定義的是int,該字段寫入資料的時候隻能是0或者1,寫入2是失敗的,

    但是往該字段寫入null值是可以的,因為null與規則指定的(0,1)相比沒有任何意義(或者沒有任何結果)

SQL Server中有關限制(constraint)的一些細節

 限制的一些特點

    對于建表的時候指定的未命名的限制,SQL Server會自動生成字尾随機的預設的限制名字,為了增加規範性,正常情況下是不允許這麼寫的,因為我們不希望看到資料庫中一堆亂七八髒的命名。

SQL Server中有關限制(constraint)的一些細節

     如果是指定限制的名字,看起來就規範多了。

SQL Server中有關限制(constraint)的一些細節

如果是通過定義規則,然後綁定到表的字段的情況下,通過SSMS的圖形界面,是看不到限制展開之後的内容的(雖然這個限制是生效的)

SQL Server中有關限制(constraint)的一些細節

 資料庫限制中那些不容易被注意的坑

    限制看起來非常簡單,不管是在建表的時候直接指定,或者是通過alter 表的方式增加限制,看起來都沒有任何問題,條條大道通羅馬,不過裡面還是有一些小坑的。

    一個資料庫中的限制不允許重名。

    也就是意味着,不同的表之間,或者表上與自定義限制之間,都不能存在同名的情況,包括主鍵限制(不能同名),檢查限制(check),預設值限制等,都不能同名

    限制的道理跟表一樣,一個庫的一個schema下中不能定義同名的表一個道理,一個庫的一個schema下不能定義同名的限制一樣。

    現在也不難了解,為什麼sqlserver預設生成的限制的名字,後面是一串随機字元了吧?

    1,表與表之間的限制不能同名

SQL Server中有關限制(constraint)的一些細節

    2,表與自定義限制名之間不能同名。

SQL Server中有關限制(constraint)的一些細節

    當然有人會說,這有什麼,定義的時候報錯就知道了,還有更大的坑。

    這裡涉及到限制的另一種定義方法,建表的過程中指定命名的主鍵限制。

    比如如下的定義臨時表的腳本,看起來沒有任何問題,也确實沒有任何問題,

    實際中遇到的一個開發人員的問題,編寫的存儲過程中定義了臨時表,定義臨時表的時候指定了命名的主鍵限制(可能是抄的實體表的定義方式),測試通過并釋出到生産環境中,一切看起來非常正常。

    釋出之後測試了兩把,也表現為正常,等到系統真正被使用者使用的時候,部分使用者回報系統(涉及到這個功能的地方)偶爾會報錯,時而正常,時而不正常(其實這種問題最難診斷的了)。

    監控應用程式會發現,某個時間段之内,發現這個存儲過程會連續地報錯一種錯誤,錯誤原因就是“無法建立索引或者限制”

    開發人員也很委屈,送出完代碼之後,明明是測試通過了的,更可惡的是,偶爾會報錯,大部分時間是正常的。

SQL Server中有關限制(constraint)的一些細節

    通過觀察其代碼,然後冷靜下來想一想,也不難了解,資料庫中的限制是不能同名的,當然臨時表生存的臨時庫也不例外,

    臨時表用完就會自動銷毀沒有錯,意味着如果所有的Session都是串行執行,這個完全沒有問題。

    但是一旦出現并發調用的情況,不同的Session會同時調用這個存儲過程,

    一旦并發調用這個存儲過程,不同的Session會建立同一個名字的限制,鐵定隻有一個會成功,這麼看,單線程測試正常,并發上來之後報錯也就不難了解了。

總結: 

    為了保證資料庫的完整性和一緻性(外鍵,本文未涉及),可以使用限制來達到這個目的,但是限制本身有自己的某些規則和特點,它跟其他資料庫對象并沒有不同的,都不允許同一個schema下存在同名的對象。

    如果沒有按照其自身的某些規則來使用,就有可能造成某些潛在的問題。

    為了規範限制的命名,在定義限制名字的時候,要嚴格遵循簡寫字首+schema+tableName+columnName的方式來定義,如果是臨時表,禁止定義命名限制。