在SQL Server中更改“默认”

时间:2012-06-30 08:53:22

标签: sql-server sql-server-2008-r2

我在SQL Server 2008表中有自定义default值。

与此相似

CREATE DEFAULT [dbo].[Default_Timestamp]
AS 
   GetDate()

现在我想更改默认值。

CREATE DEFAULT [dbo].[Default_Timestamp]
AS 
   GETUTCDATE()

在我可以编辑现有的之前,我需要删除第一个并重新创建它。

DROP DEFAULT [dbo].[Default_Timestamp]

它会出现以下错误。

  

Msg 3716,Level 16,State 3,Line 4
  无法删除默认的“dbo.Default_Timestamp”,因为它绑定到一个或多个列。

由于默认值已被少数表使用,因此我无法删除并重新创建新表。

我知道在重新创建它之前,我需要取消绑定此默认表中的所有表。

是否有人可以提供脚本来列出与该默认值绑定的所有表和列?

4 个答案:

答案 0 :(得分:4)

这是一个多步骤的过程:

1)找到默认的object_id

DECLARE @DefaultObjectID INT
SELECT @DefaultObjectID = OBJECT_ID('Default_Timestamp')

2)找到引用该默认值的所有列:

SELECT 
    ColumnName = c.Name,
    TableName = t.Name,
    UnbindCmd = 'EXEC sp_unbindefault ''' + t.Name + '.' + c.name + ''''
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE default_object_id = @DefaultObjectID

这将生成一个UnbindCmd命令列表,以便从这些列中实际删除DEFAULT

3)现在,从SQL Server Mgmt Studio窗口复制该列,并在新的查询窗口中执行该列,以实际“取消绑定”所有这些列的默认值

4)现在定义新的默认

但是:这些天,我可能定义一个新的DEFAULT本身 - 你不能只在列中设置默认约束问题直接?

ALTER TABLE dbo.YourTable
ADD CONSTRAINT DF_YourTable_TimeStamp
DEFAULT GETUTCDATE() FOR YourColumnName

似乎更容易与未来合作!当您明确命名约束时,如果需要,您还可以轻松地再次查找和删除该约束。

答案 1 :(得分:1)

我从未将CREATE DEFAULT或DROP DEFAULT视为独立命令,但只知道CONSTRAINT子句添加或删除默认约束。

SSMS 2008生成以下代码(右键单击表设计器,“生成更改脚本...”):

ALTER TABLE dbo.T ADD CONSTRAINT
    DF_T_DateTimeColumn DEFAULT getdate() FOR DateTimeColumn
GO

ALTER TABLE dbo.T
    DROP CONSTRAINT DF_T_DateTimeColumn
GO
ALTER TABLE dbo.T ADD CONSTRAINT
    DF_T_DateTimeColumn DEFAULT getutcdate() FOR DateTimeColumn
GO

更新

我承认,我从未使用过EXEC sp_bindefault,但我认为不鼓励使用它,因为MSDN说:

  

将在Microsoft SQL的未来版本中删除此功能   服务器。不要在新的开发工作中使用此功能,并进行修改   目前正在使用此功能的应用程序。我们   建议您使用DEFAULT创建默认定义   取而代之的是ALTER TABLE或CREATE TABLE语句的关键字。

当然,这也适用于sp_unbindefault

答案 2 :(得分:1)

通过查看sys.columns中的default_object_id,您可以找到使用默认对象的列:

  

默认对象的ID,无论它是否为独立对象   object sys.sp_bindefault,或内联的列级DEFAULT   约束

知道这对于构建一个脚本来解决默认对象中的所有列并使用基于约束的默认值替换默认值是微不足道的:

use master;
go

if db_id('test') is not null
    drop database test;
go

create database test;
go

use test;
go

create default foo as 1;
go

create table t1 (a int);
create table t2 (b int);
go

exec sp_bindefault 'foo', 't1.a';
exec sp_bindefault 'foo', 't2.b';
go

drop default foo;
-- Msg 3716, Level 16, State 3, Line 2
-- The default 'foo' cannot be dropped because it is bound to one or more column.
go

declare crs cursor static forward_only read_only for
select object_schema_name(object_id) as schema_name,
        object_name(object_id) as object_name,
        name as column_name
    from sys.columns where default_object_id = object_id('foo');
open crs;

declare @schema_name sysname, @object_name sysname, @column_name sysname, @sql nvarchar(max);

fetch next from crs into @schema_name, @object_name, @column_name;
while @@fetch_status = 0
begin
    set @sql = N'exec sp_unbindefault ' + quotename(
        quotename(@schema_name) + N'.'+
        quotename(@object_name) + N'.'+
        quotename(@column_name), '''');
    print @sql;
    exec sp_executesql @sql;
    set @sql = N'alter table ' +
        quotename(@schema_name) + N'.' + 
        quotename(@object_name) + N' add constraint ' + 
        quotename(N'default_' + @column_name) + N' default 2 for ' +
        quotename(@column_name);
    print @sql;
    exec sp_executesql @sql;
    fetch next from crs into @schema_name, @object_name, @column_name;
end

close crs;
deallocate crs;
go

drop default foo;
-- it now succeeds
go

答案 3 :(得分:1)

当我在数据库中发现一些旧的默认值时,我不得不遇到这个问题,我不得不在数据库中批量更新uses_ansi_nulls和uses_quoted_identifier。

这是我最后写的代码,用较新的样式(ALTER TABLE)替换了旧样式的默认值(CREATE DEFAULT sp_BindDefault)。

DECLARE @strSQL varchar(max)
        , @DBName varchar(50) = DB_NAME();

DROP TABLE IF EXISTS #tmp;

SELECT  IDENTITY(int, 1,1) AS ID,
        UnbindCmd = 'EXEC sp_unbindefault ''' + t.Name + '.' + c.name + ''';',
        DropCmd = 'DROP DEFAULT IF EXISTS [' + SCHEMA_NAME(SO.schema_id) + '].[' + OBJECT_NAME(SO.object_id) + '];',
        CreateCmd = 'ALTER TABLE [' + SCHEMA_NAME(t.Schema_id) + '].[' + t.Name + ']'
                    + ' ADD CONSTRAINT df_' + REPLACE(t.Name, ' ', '') + '_' + REPLACE(c.Name, ' ', '')
                    + ' DEFAULT (' + RIGHT(m.definition, LEN(m.definition) - CHARINDEX(' AS ', m.definition) - 3)
                    + ') FOR ' + QUOTENAME(c.Name) + ';'
INTO    #tmp
FROM    sys.sql_modules m
        join sys.columns c on c.default_object_id = m.object_id
        INNER JOIN sys.tables t ON c.object_id = t.object_id
        JOIN sys.objects SO ON SO.object_id = C.default_object_id
WHERE   (m.uses_ansi_nulls = 0 
        OR m.uses_quoted_identifier = 0)
ORDER BY
        t.name
        , c.name;

BEGIN TRANSACTION
    BEGIN TRY
        DECLARE UnbindCursor CURSOR LOCAL FAST_FORWARD
        FOR SELECT  UnbindCmd
            FROM    #tmp
            ORDER BY
                    ID;

        OPEN UnbindCursor;

        FETCH NEXT FROM UnbindCursor INTO @strSQL;

        WHILE @@FETCH_STATUS = 0
            BEGIN
                EXEC (@strSQL);

                FETCH NEXT FROM UnbindCursor INTO @strSQL;
            END

        CLOSE UnbindCursor;
        DEALLOCATE UnbindCursor;

        DECLARE DropCursor CURSOR LOCAL FAST_FORWARD
        FOR SELECT  DropCmd
            FROM    #tmp
            GROUP BY
                    DropCmd
            ORDER BY
                    MIN(id)

        OPEN DropCursor;

        FETCH NEXT FROM DropCursor INTO @strSQL;

        WHILE @@FETCH_STATUS = 0
            BEGIN
                EXEC (@strSQL);

                FETCH NEXT FROM DropCursor INTO @strSQL;
            END

        CLOSE DropCursor;
        DEALLOCATE DropCursor;

        DECLARE CreateCursor CURSOR LOCAL FAST_FORWARD
        FOR SELECT  CreateCmd
            FROM    #tmp
            ORDER BY
                    id

        OPEN CreateCursor;

        FETCH NEXT FROM CreateCursor INTO @strSQL;

        WHILE @@FETCH_STATUS = 0
            BEGIN
                EXEC (@strSQL);

                FETCH NEXT FROM CreateCursor INTO @strSQL;
            END

        CLOSE CreateCursor;
        DEALLOCATE CreateCursor;

        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        DECLARE @ErrorMessage nvarchar(4000)
                , @ErrorSeverity int
                , @ErrorState int;

        SELECT   
            @ErrorMessage = ERROR_MESSAGE(),
            @ErrorSeverity = ERROR_SEVERITY(),  
            @ErrorState = ERROR_STATE();  

        IF XACT_STATE() <> 0 ROLLBACK TRANSACTION;

        RAISERROR (@ErrorMessage, -- Message text.  
                    @ErrorSeverity, -- Severity.  
                    @ErrorState -- State.  
                    );  
    END CATCH