每周我的客户都会向我发送一个数据库,其中包含一个非常大的表,没有主键,并且其中具有唯一 ID 的列可以为空。
所以我运行ALTER TABLE
将我想要作为主键的列设置为 NOT NULL:
ALTER TABLE Live1.dbo.Orders
ALTER COLUMN OrderID varchar(10) NOT NULL;
然后在完成大约 45 分钟后,我添加了我的主键:
ALTER TABLE Live1.dbo.Orders
ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID)
到目前为止一切都很好。
在那之前,我会尝试自动化这个漫长而乏味的操作。
我创建了一个非常简单的存储过程,它会在我的客户数据库完成恢复后立即运行,作为代理作业的一部分:
CREATE PROCEDURE dbo.AddPKey
AS
BEGIN
SET NOCOUNT ON;
ALTER TABLE Live1.dbo.Orders ALTER COLUMN OrderID varchar(10) NOT NULL;
ALTER TABLE Live1.dbo.Orders ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID)
END
GO
这在 1 秒后失败,并显示错误消息:
无法对表“订单”中的可为空列定义 PRIMARY KEY 约束。[SQLSTATE 42000](错误 8111)无法创建约束或索引。请参阅以前的错误。[SQLSTATE 42000](错误 1750)。步骤失败。
ALTER COLUMN
所以它试图在上一步完成之前设置主键约束。在尝试添加主键约束之前应该至少需要 45 分钟,但它会尝试立即添加。如果我ALTER COLUMN
手动运行,它工作得很好。
是什么赋予了?我写了几十个存储过程,但没有一个是那样的?
我能做些什么来强迫它等待?我以为这就是ALTER COLUMN
行尾的分号所做的?
更新:
非常感谢 π 对这里实际发生的事情的深刻回答和澄清。我的最终存储过程如下所示:
DECLARE @DynamicSQL nvarchar(4000)
ALTER TABLE Live1.dbo.Orders ALTER COLUMN OrderID varchar(10) NOT NULL;
SET @DynamicSQL = 'ALTER TABLE Live1.dbo.Orders
ADD CONSTRAINT PK_OrdersOrderID PRIMARY KEY CLUSTERED (OrderID);'
EXEC Live1.sys.sp_executesql @DynamicSQL
哪个没有错误:)