SQL Server如何保證可空字段中非空值唯一

2021-06-04 19:02:03 字數 3263 閱讀 6612

今天同學向我提了乙個問題,是sql server中乙個關於「如何保證可空字段中非空值唯一」的問題,我覺得蠻有意思,現記錄下來大家**下。

問題是:在乙個表裡面,有乙個允許為空的字段,空是可以重複的,但是不為空的值需要唯一。

表結構如下面**建立

create

table

test_tb  

(  testid 

intnot

null

identity(1,1) 

primary

key,  

caption nvarchar(100) 

null

);  

go  

解決方案:

解決方案1:

對於這個問題,大家的第乙個想法可能是:在caption這個字段上面加乙個唯一鍵不就可以了嗎?好,我們按著這個思路做下去,先建立唯一索引。

create

unique

nonclustered 

index

un_test_tb   

ontest_tb(caption)  

go  

索引建立好了,我們來測試下效果

insert

into

test_tb (caption)  

values

(null

)  go  

insert

into

test_tb (caption)  

values

(null

)  go  

執行之後我們會收到下面的錯誤資訊:

訊息 2601,級別 14,狀態 1,第 1 行  

不能在具有唯一索引 

'un_test_tb'

的物件 

'dbo.test_tb'

中插入重複鍵的行。  

語句已終止。  

所以該解決方案是不行的。

解決方案2:

新增約束,讓sql server在插入資料的時候,先驗證下已有資料中是否有現在要插入的這個值。由於這個約束不是簡單的乙個運算,因此我們先建立乙個函式,然後再在約束中呼叫這個函式。

建立驗證邏輯函式:

create

function

[dbo].[fn_ck_test_tb_caption]()  

returns

bitas

begin

if(exists(  

select

1  from

test_tb 

asa  

where

(caption 

isnot

null

) and

exists  

(select

1 as

expr1  

from

test_tb  

where

(caption 

isnot

null

) and

(caption = a.caption) 

and(a.testid <> testid))  

))  

return

0  return

1  end

go  

在約束中引用函式:

alter

table

test_tb  

addconstraint

ck_test_tb_caption 

check

(dbo.fn_ck_test_tb_caption() = 1)  

go  

現在來測試下效果。先來測試null值

insert

into

test_tb (caption)  

values

(null

)  go  

insert

into

test_tb (caption)  

values

(null

)  go  

select

* from

test_tb  

go  

可以成功執行,而且也出了多行為null的情況。現在再來測試不為空的插入情況。

insert

into

test_tb (caption)  

values

(n'aaa'

)  go  

insert

into

test_tb (caption)  

values

(n'bbb'

)  go  

insert

into

test_tb (caption)  

values

(n'bbb'

)  go  

select

* from

test_tb  

go  

結果是在第三條語句的時候報錯了,表中的caption欄位也有'aaa'和'bbb'了,這也正好是我們要的結果。

所以解決方案2是正確的。但是為了這麼乙個小小功能,就寫這麼長一段東西是不是太繁瑣了呢?我們來看下面的解決方案。

解決方案3:(只適用於sql server 2008)

sql server 2008中有了乙個優雅的解決方案,那就是篩選索引。篩選索引是一種經過優化的非聚集索引,尤其適用於涵蓋從定義完善的資料子集中選擇資料的查詢。篩選索引使用篩選謂詞對錶中的部分行進行索引。有了篩選索引,我們只需要寫一條語句就達到上面的效果。

create

unique

nonclustered 

index

un_test_tb   

ontest_tb(caption)  

where

caption 

isnot

null

go  

再用上面的一些測試語句來測試的話,會發現完全是達到了我們的要求。

這個方案的唯一缺點就是該語句只有sql server 2008支援。。

不知道各位有沒有又優雅又適用於各個版本的sql server的解決方案,望不勝賜教。

SQL Server如何保證可空字段中非空值唯一

今天同學向我提了乙個問題,是sql server中乙個關於 如何保證可空字段中非空值唯一 的問題,我覺得蠻有意思,現記錄下來大家 下。問題是 在乙個表裡面,有乙個允許為空的字段,空是可以重複的,但是不為空的值需要唯一。表結構如下面 建立 create table test tb testid int...

SQL Server如何保證可空字段中非空值唯一

今天同學向我提了乙個問題,是sql server中乙個關於 如何保證可空字段中非空值唯一 的問題,我覺得蠻有意思,現記錄下來大家 下。問題是 在乙個表裡面,有乙個允許為空的字段,空是可以重複的,但是不為空的值需要唯一。表結構如下面 建立 create table test tb testid int...

SQL Server如何保證可空字段中非空值唯一

今天同學向我提了乙個問題,是sql server中乙個關於 如何保證可空字段中非空值唯一 的問題,我覺得蠻有意思,現記錄下來大家 下。問題是 在乙個表裡面,有乙個允許為空的字段,空是可以重複的,但是不為空的值需要唯一。表結構如下面 建立 create table test tb testid int...