SSMS 约束脚本:第二个alter table 语句的目的?

Pau*_*mes 5 foreign-key sql-server constraint ssms scripting

SSMS 脚本外键约束为两个语句:

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

ALTER TABLE {table}
CHECK CONSTRAINT {constraintname}
GO
Run Code Online (Sandbox Code Playgroud)

第二个陈述的目的是什么?

Tom*_*m V 6

第二行是多余的,但我同意该CHECK语法中的过度使用令人困惑。

根据ALTER TABLE 文档,如果使用该WITH CHECK ADD选项并启用新添加的约束,无论如何都会检查现有数据。

带检查 | WITH NOCHECK
指定是否根据新添加或重新启用的 FOREIGN KEY 或 CHECK 约束验证表中的数据。如果未指定,则为新约束假定 WITH CHECK,并为重新启用的约束假定 WITH NOCHECK。

第二行再次从文档中启用约束,但该约束已经启用。

{ 检查 | NOCHECK } CONSTRAINT 指定启用或禁用constraint_name。此选项只能与 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)
Run Code Online (Sandbox Code Playgroud)

结果是:

消息 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
Run Code Online (Sandbox Code Playgroud)

返回:

(受影响的 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
Run Code Online (Sandbox Code Playgroud)

这仍然会导致显示外键已启用的错误:

消息 547 级别 16 状态 0 第 1 行 INSERT 语句与 FOREIGN KEY 约束“FK_valuetable_keytable”冲突。冲突发生在数据库“fiddle_7378e515ee284b358b4e2edbc07d1329”、表“dbo.keytable”、“key”列中。消息 3621 级别 0 状态 0 行 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
Run Code Online (Sandbox Code Playgroud)

返回:

消息 547 级别 16 状态 0 第 1 行 ALTER TABLE 语句与 FOREIGN KEY 约束“FK_valuetable_keytable”冲突。冲突发生在数据库“fiddle_59761b4587c14f2b96b8029a10de6229”、表“dbo.keytable”、“key”列中。

dbfiddle在这里

  • 汤姆,谢谢你做证明。听起来第二个说法是多余的。我想确保我没有遗漏一些东西,更糟糕的是——根据我自己的情况引导我们的团队养成坏习惯。 (2认同)