Sql-Server

SSMS 約束腳本:第二條 alter table 語句的用途?

  • August 18, 2017

SSMS 將外鍵約束腳本編寫為兩個語句:

ALTER TABLE {table}
WITH CHECK
ADD CONSTRAINT {constraintname} {constraint spec}
GO

ALTER TABLE {table}
CHECK CONSTRAINT {constraintname}
GO

第二個聲明的目的是什麼?

第二行是多餘的,但我同意過度使用CHECK該語法會令人困惑。

根據ALTER TABLE 文件WITH CHECK ADD,如果使用該選項並且啟用了新添加的約束,則無論如何都會檢查現有數據。

帶支票 | WITH NOCHECK

指定表中的數據是否針對新添加或重新啟用的 FOREIGN KEY 或 CHECK 約束進行驗證。如果未指定,則假定 WITH CHECK 用於新約束,而 WITH NOCHECK 假定用於重新啟用的約束。

第二行再次從文件中啟用約束,但該約束已經啟用。

{檢查| NOCHECK } CONSTRAINT 指定啟用或禁用約束名稱。此選項只能與 FOREIGN KEY 和 CHECK 約束一起使用。當指定 NOCHECK 時,約束被禁用,並且將來對列的插入或更新不會根據約束條件進行驗證。不能禁用 DEFAULT、PRIMARY KEY 和 UNIQUE 約束。

但是,約束已經啟用,從這段程式碼可以看出:

CREATE TABLE [dbo].[constraintdemo](
   [constraintfield] [int] NULL
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[constraintdemo]  WITH CHECK ADD  CONSTRAINT [CK_constraintdemo] CHECK  (([constraintfield]>(0)))
GO

INSERT INTO constraintdemo (constraintfield) VALUES (-1)

結果是:

消息 547,級別 16,狀態 0,第 12 行 INSERT 語句與 CHECK 約束“CK_constraintdemo”衝突。衝突發生在數據庫“PlayGround”、表“dbo.constraintdemo”、列“constraintfield”中。該語句已終止。

請參閱此dbfiddle,您可以在其中執行上述程式碼

如果您想證明現有數據已被有效驗證,WITH CHECK您可以執行以下程式碼:

CREATE TABLE [dbo].[constraintdemo](
   [constraintfield] [int] NULL
) ON [PRIMARY]

GO

INSERT INTO constraintdemo (constraintfield) values (-1),(-2)
GO

ALTER TABLE [dbo].[constraintdemo]  WITH CHECK ADD  CONSTRAINT [CK_constraintdemo] CHECK  (([constraintfield]>(0)))
GO

返回:

(2 行受影響)消息 547,級別 16,狀態 0,第 21 行 ALTER TABLE 語句與 CHECK 約束“CK_constraintdemo”衝突。衝突發生在數據庫“PlayGround”、表“dbo.constraintdemo”、列“constraintfield”中。

再次:dbfiddle

在這個例子中,它是檢查約束還是外鍵約束並不重要,正如這個稍微複雜的例子所證明的那樣(注意我註釋掉了第二行):

CREATE TABLE [dbo].[keytable](
   [key] [nchar](10) NOT NULL,
CONSTRAINT [PK_keytable] PRIMARY KEY CLUSTERED 
(
   [key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[valuetable](
   [key] [nchar](10) NULL,
   [value] [nchar](10) NULL
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[valuetable]  WITH CHECK ADD  CONSTRAINT [FK_valuetable_keytable] FOREIGN KEY([key])
REFERENCES [dbo].[keytable] ([key])
GO

--ALTER TABLE [dbo].[valuetable] CHECK CONSTRAINT [FK_valuetable_keytable]
GO

INSERT INTO keytable ([key]) VALUES (1),(2);
GO

INSERT INTO valuetable ([key],[value]) VALUES (3,'test');
GO

這仍然會導致顯示外鍵已啟用的錯誤:

消息 547 級別 16 狀態 0 第 1 行 INSERT 語句與 FOREIGN KEY 約束“FK_valuetable_keytable”衝突。衝突發生在數據庫“fiddle_7378e515ee284b358b4e2edbc07d1329”、表“dbo.keytable”、“key”列中。Msg 3621 Level 0 State 0 Line 1

語句已終止。

Dbfiddle在這裡

再一次,我們可以扭轉局面,證明它使用以下程式碼檢查創建時的現有數據:

CREATE TABLE [dbo].[keytable](
   [key] [nchar](10) NOT NULL,
CONSTRAINT [PK_keytable] PRIMARY KEY CLUSTERED 
(
   [key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[valuetable](
   [key] [nchar](10) NULL,
   [value] [nchar](10) NULL
) ON [PRIMARY]

GO
INSERT INTO keytable ([key]) VALUES (1),(2);
GO

INSERT INTO valuetable ([key],[value]) VALUES (3,'test');
GO

ALTER TABLE [dbo].[valuetable]  WITH CHECK ADD  CONSTRAINT [FK_valuetable_keytable] FOREIGN KEY([key])
REFERENCES [dbo].[keytable] ([key])
GO

返回:

消息 547 級別 16 狀態 0 第 1 行 ALTER TABLE 語句與 FOREIGN KEY 約束“FK_valuetable_keytable”衝突。衝突發生在數據庫“fiddle_59761b4587c14f2b96b8029a10de6229”、表“dbo.keytable”、列“key”中。

dbfiddle在這裡

引用自:https://dba.stackexchange.com/questions/183736