在SQL 2008中更新列的可空性

时间:2010-04-08 08:48:22

标签: sql-server sql-server-2008 ssms

我有一个非常宽的表,包含许多位字段。这些位字段最初设置为可空。现在我们刚刚决定让它们可以为空而没有意义;值为“是”或“否”,默认为“否”。换句话说,架构应更改为:

create table MyTable( 
  ID bigint not null,
  Name varchar(100) not null,
  BitField1 bit null,
  BitField2 bit null,
  ...
  BitFieldN bit null
)

create table MyTable( 
  ID bigint not null,
  Name varchar(100) not null,
  BitField1 bit not null,
  BitField2 bit not null,
  ...
  BitFieldN bit not null
)

alter table MyTable add constraint DF_BitField1 default 0 for BitField1
alter table MyTable add constraint DF_BitField2 default 0 for BitField2
alter table MyTable add constraint DF_BitField3 default 0 for BitField3

所以我刚刚进入SQL Management Studio,将所有这些字段更新为不可为空,默认值为0.并猜测是什么 - 当我尝试更新它时,SQL Mgmt studio在内部重新创建表,然后尝试将所有数据重新插入到新表中...包括空值!这当然会产生错误,因为它明确地尝试将空值插入到不可为空的列中。 Aaargh!

显然我可以运行以下格式的N更新语句:

update MyTable set BitField1 = 0 where BitField1 is null
update MyTable set BitField2 = 0 where BitField2 is null

但正如我之前所说,那里有 n 字段,而且此更改必须传播到几个相同的数据库。手动实施非常痛苦。

是否有任何方法可以使表修改忽略空值并允许默认规则在您尝试插入空值时启动?

3 个答案:

答案 0 :(得分:2)

如果您完全确定要对所有表中的位列执行此操作,则可以使用游标迭代这些列并动态构建脚本。这类似于亚历山大的解决方案,除非它的列号没有编号为1..n(我怀疑 - 我猜这些可能是为了说明目的而简化了)。

DECLARE @colName sysname;
DECLARE @sql nvarchar(max);

DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
    SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'MyTable' AND DATA_TYPE = 'bit' AND IS_NULLABLE = 'YES';

OPEN cur;

FETCH NEXT FROM cur INTO @colName;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = N'UPDATE [MyTable] SET ' + QUOTENAME(@colName)
        + N' = 0 WHERE ' + QUOTENAME(@colName) + N' IS NULL;'
        + N'ALTER TABLE [MyTable] ALTER COLUMN ' + QUOTENAME(@colName)
        + N' bit NOT NULL;'
        + N'ALTER TABLE [MyTable] ADD CONSTRAINT ' + QUOTENAME('DF_' + @colName)
        + N' DEFAULT(0) FOR ' + QUOTENAME(@colName) + N';';

    EXEC (@sql); -- Replace with PRINT @sql; if you want to test first.

    FETCH NEXT FROM cur INTO @colName;
END

CLOSE cur;
DEALLOCATE cur;

答案 1 :(得分:0)

我认为毕竟我只想使用N更新语句。 编写脚本是一次性的工作,主要是复制和粘贴,然后我可以在所有适用的数据库上运行该脚本。

尽管如此,我仍然有兴趣知道是否还有另一种更有效的方法......

答案 2 :(得分:0)

DECLARE @command VARCHAR(8000)
DECLARE @index int
SET @index=0
WHILE @index<=N DO BEGIN
 SET @command=@command+'update MyTable SET BitField'+cast(@index as varchar(3))+' = 0 WHERE BitField'+cast(@index as varchar(3))+' IS NULL'
 EXEC(@command)
 SET @index=@index+1
END

依旧......