開發提了乙個資料庫變更需求,新增一欄位,沒有not null非空約束,但有預設值為null。看起來有些奇怪,因為若欄位允許null,其預設值就是null,不用顯示宣告,可以建立乙個無default null的新增欄位再檢視desc表結構,就可以證明這點。
基於這問題,引申出的not null欄位問題還有不少,也是比較容易忽視的一些細節,例如楊長老最近連續發表過兩篇關於not null欄位的文章確實很有啟發,
非空字段空值對查詢的影響
?p=1481
非空字段空值的產生
?p=1483
具體各位可以參考這兩篇博文,簡單總結一下,11.2.0.3的庫,
1.使用where type is null和is not null得到的記錄結果判斷值為非空。
2.使用dump(type)和nvl(type, 『is null』)得到的記錄結果判斷值為空。
表定義中此字段為default 」 not null,事實證明(2)是正確的,之所以有(1)的結論,原因是cbo太智慧型了。
對於is not null,type欄位定義為not null,此sql明顯違反了表中的約束條件,則會在執行計畫最上層增加乙個null is not null恒為假的條件,根本不需要真正執行這個sql,直接返回0條記錄。
對於is null,由於查詢條件滿足約束的條件,因此oracle會做全表掃瞄,並且省略了type is not null的過濾,直接返回所有記錄,就造成了type非空的假象。
出現以上問題的核心,還是為何有為空的記錄儲存於有not null非空約束的表中。原因就是11g新特性,新增乙個有預設值的not null約束的字段,預設值不會像以前一樣,插入每條記錄中,而是會儲存於一張資料字典表sys.ecol$,oracle允許not null列預設值為null,因此對於11g來說,需要禁止default為null的這種行為。
這種新增非空約束欄位在不同版本中確實有一些細節的變化,下面做一些簡單測試。
首先,建立測試表,插入一條資料,新增列為not null且預設值是」的字段:
create
table bisal (id number);
insert
into bisal values(1);
alter
table bisal add name varchar2(10) default
''not
null;
10.2.0.3庫,從報錯資訊看ora-01407,不能更新name列為空,可以看出此時是要將表中已存在記錄的新列name做update設定為預設值的操作,由於有非空約束,因此不允許。
11.2.0.1庫,可以新增字段,表中已存記錄該值確實為空,即允許乙個有not null約束的字段包含null值。
關於這新特性的好處,可以參考之前寫的
《alter table新增字段操作究竟有何影響?(上下篇)》
12.1.0.2庫,我們可以看出和10g一樣,禁止新增乙個預設值為null的not null約束字段,但報錯資訊變了,ora-01758: table must be empty to add mandatory (not null) column,這個錯誤號在之前的版本有定義,不是新號。
根據錯誤提示,我們刪除表中資料,再新增字段,可以增加,但不能再插入一條null至這個非空約束字段。
我們再看下官方文件的描述,11g中對於新增預設值欄位的描述部分,明確指出not null約束包含預設值的情況下,是將預設值儲存於資料字典中。
12c中描述允許為空的字段,若有預設值,不會更新已存資料,而是會借助資料字典完成儲存,這種新特性的適用範圍更廣了。
由於我沒有12c的sys真實環境,朋友可以自己嘗試下,有機會我會自己再驗證下。
至此,12c修復了11g中這個非空約束字段允許儲存空值的bug,同時又支援11g新增預設值非空字段使用資料字典儲存的特性,並且做了擴充套件支援,滿足範圍更大了。
小問題隱藏了大智慧型。
查詢表中的總字段數 空欄位與非空欄位
select count 總字段數,isnull isnull sum case when isnullable 0 then 1 end null null as 非空字段數 from syscolumns where id object id t user 空欄位總數 select select...
mysql非空約束兩個 MySQL中的或非空約束
sklivz 使用mysql5.0.51a進行測試時,我發現它解析了乙個檢查約束,但沒有強制執行它。我可以插入 空,空 而不出錯。測試了myisam和innodb。隨後使用show create table顯示檢查約束不在表定義中,即使在定義表時沒有給出任何錯誤。這與mysql manual 它說 ...
truncate在不同版本中的區別
中午和同事討論truncate到底會不會釋放資源,大部分都認為會,但是其實具體情況是和mysql的版本有關。before 5.0.3 truncate是delete rows one by one。between 5.0.3 and 5.0.8 當有外來鍵的時候還是delete rows one b...