使列不可为空所需的代码

Álv*_*lez 5 sql-server-2008 sql-server ssms t-sql

我有一个表,我错误地在列中允许 NULL 值:

CREATE TABLE EXAMPLE (
    EXAMPLE_ID INT IDENTITY(1, 1) NOT NULL,
    FOO_ID INT,
    CREATED_ON DATETIME DEFAULT CURRENT_TIMESTAMP, -- Oops!
    CODE VARCHAR(50),
    QUOTE DECIMAL(18,2),
    BAR_ID TINYINT NOT NULL DEFAULT 1,

    CONSTRAINT EXAMPLE_PK PRIMARY KEY (EXAMPLE_ID),

    CONSTRAINT EXAMPLE_FK1 FOREIGN KEY (FOO_ID)
    REFERENCES FOO (FOO_ID)
    ON DELETE CASCADE,

    CONSTRAINT EXAMPLE_FK2 FOREIGN KEY (BAR_ID)
    REFERENCES BAR (BAR_ID)
);

CREATE INDEX EXAMPLE_IDX1 ON EXAMPLE (FOO_ID);
CREATE INDEX EXAMPLE_IDX2 ON EXAMPLE (BAR_ID);
Run Code Online (Sandbox Code Playgroud)

这是一个相当不重要的列(没有索引,没有外键,没有在触发器中使用......),这是我通常修复它的方式:

ALTER TABLE EXAMPLE
ALTER COLUMN CREATED_ON DATETIME NOT NULL;
-- Runs in 1 second
Run Code Online (Sandbox Code Playgroud)

但是,我决定使用 GUI 工具(SQL Server Management Studio,但我尝试过的所有其他工具都做类似的事情),发现整个过程大约需要 20 分钟。原因?自动生成的更改代码是一个 3351 行的脚本,它显然试图编辑数据库中具有指向EXAMPLE.EXAMPLE_ID!

ALTER TABLE dbo.SOME_OTHER_TABLE
DROP CONSTRAINT SOME_OTHER_TABLE_FK
GO


BEGIN TRANSACTION
GO
ALTER TABLE dbo.SOME_OTHER_TABLE ADD CONSTRAINT
    SOME_OTHER_TABLE_FK FOREIGN KEY
    (
        EXAMPLE_ID
    ) REFERENCES dbo.EXAMPLE
    (
        EXAMPLE_ID
    ) ON UPDATE  NO ACTION
    ON DELETE  CASCADE

GO
ALTER TABLE dbo.SOME_OTHER_TABLE SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
Run Code Online (Sandbox Code Playgroud)

进一步挖掘表明,该脚本Tmp_EXAMPLE使用最终定义创建了一个新表,并将所有数据从EXAMPLE.

这个复杂的过程有必要吗?plain 的确切问题是ALTER TABLE什么?

Hyb*_*s95 1

NULL只需将当前值更新为默认值即可。
然后做你的ALTER TABLE

整数示例

UPDATE [MyTable]
SET [MyColumn] = 0
WHERE [MyColumn] IS NULL;
ALTER TABLE [MyTable] ALTER COLUMN [MyColumn] INTEGER NOT NULL;
Run Code Online (Sandbox Code Playgroud)

varchar 的示例

UPDATE [MyTable]
SET [MyColumn] = ''
WHERE [MyColumn] IS NULL;
ALTER TABLE [MyTable] ALTER COLUMN [MyColumn] VARCHAR(max) NOT NULL;
Run Code Online (Sandbox Code Playgroud)

更改列: null 为 not null

安全措施

在此之前,请确保备份数据库,以防万一搞砸了

简短地说

SSMS 制作的整个复杂场景是没有必要的,做一个简单的场景是没有问题的ALTER TABLE