我想在要用GUID填充的列上具備惟一約束。 可是,個人數據包含此列的空值。 如何建立容許多個空值的約束? sql
這是一個示例方案 。 考慮如下模式: 數據庫
CREATE TABLE People ( Id INT CONSTRAINT PK_MyTable PRIMARY KEY IDENTITY, Name NVARCHAR(250) NOT NULL, LibraryCardId UNIQUEIDENTIFIER NULL, CONSTRAINT UQ_People_LibraryCardId UNIQUE (LibraryCardId) )
而後查看此代碼以瞭解我要實現的目標: 架構
-- This works fine: INSERT INTO People (Name, LibraryCardId) VALUES ('John Doe', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'); -- This also works fine, obviously: INSERT INTO People (Name, LibraryCardId) VALUES ('Marie Doe', 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB'); -- This would *correctly* fail: --INSERT INTO People (Name, LibraryCardId) --VALUES ('John Doe the Second', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA'); -- This works fine this one first time: INSERT INTO People (Name, LibraryCardId) VALUES ('Richard Roe', NULL); -- THE PROBLEM: This fails even though I'd like to be able to do this: INSERT INTO People (Name, LibraryCardId) VALUES ('Marcus Roe', NULL);
最後一條語句失敗,並顯示一條消息: app
違反UNIQUE KEY約束'UQ_People_LibraryCardId'。 沒法在對象「 dbo.People」中插入重複密鑰。 less
如何更改架構和/或惟一性約束,以便容許多個NULL
值,同時仍檢查實際數據的惟一性? 測試
您不能使用UNIQUE
約束來執行此操做,可是能夠在觸發器中執行此操做。 this
CREATE TRIGGER [dbo].[OnInsertMyTableTrigger] ON [dbo].[MyTable] INSTEAD OF INSERT AS BEGIN SET NOCOUNT ON; DECLARE @Column1 INT; DECLARE @Column2 INT; -- allow nulls on this column SELECT @Column1=Column1, @Column2=Column2 FROM inserted; -- Check if an existing record already exists, if not allow the insert. IF NOT EXISTS(SELECT * FROM dbo.MyTable WHERE Column1=@Column1 AND Column2=@Column2 @Column2 IS NOT NULL) BEGIN INSERT INTO dbo.MyTable (Column1, Column2) SELECT @Column2, @Column2; END ELSE BEGIN RAISERROR('The unique constraint applies on Column1 %d, AND Column2 %d, unless Column2 is NULL.', 16, 1, @Column1, @Column2); ROLLBACK TRANSACTION; END END
當我在下面應用惟一索引時: spa
CREATE UNIQUE NONCLUSTERED INDEX idx_badgeid_notnull ON employee(badgeid) WHERE badgeid IS NOT NULL;
每一個非null更新和插入均失敗,並顯示如下錯誤: code
UPDATE失敗,由於如下SET選項具備錯誤的設置:'ARITHABORT'。 server
我在MSDN上找到了
在計算列或索引視圖上建立或更改索引時,SET ARITHABORT必須爲ON。 若是SET ARITHABORT爲OFF,則對在計算列或索引視圖上具備索引的表執行CREATE,UPDATE,INSERT和DELETE語句將失敗。
所以,爲了使其正常工做,我這樣作了
右鍵單擊[數據庫]->屬性->選項->其餘選項->其餘->啓用算術停止-> true
我相信能夠在代碼中使用
ALTER DATABASE "DBNAME" SET ARITHABORT ON
但我尚未測試
對於正在使用Microsoft SQL Server Manager並想要建立惟一但可爲空的索引的用戶,您能夠像一般那樣建立惟一索引,而後在新索引的索引屬性中,從左側面板中選擇「過濾器」,而後輸入您的過濾器(這是您的where子句)。 它應顯示以下內容:
([YourColumnName] IS NOT NULL)
這適用於MSSQL 2012
如前所述,SQL Server在UNIQUE CONSTRAINT
方面未實現ANSI標準。 自2007年以來,Microsoft Connect上已經有一張票。如此處和此處所述,到目前爲止,最好的選擇是使用另外一個答案中列出的過濾索引或計算列,例如:
CREATE TABLE [Orders] ( [OrderId] INT IDENTITY(1,1) NOT NULL, [TrackingId] varchar(11) NULL, ... [ComputedUniqueTrackingId] AS ( CASE WHEN [TrackingId] IS NULL THEN '#' + cast([OrderId] as varchar(12)) ELSE [TrackingId_Unique] END ), CONSTRAINT [UQ_TrackingId] UNIQUE ([ComputedUniqueTrackingId]) )
CREATE UNIQUE NONCLUSTERED INDEX [UIX_COLUMN_NAME] ON [dbo].[Employee]([Username] ASC) WHERE ([Username] IS NOT NULL) WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, STATISTICS_NORECOMPUTE = OFF, ONLINE = OFF, MAXDOP = 0) ON [PRIMARY];