3

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

与此类似

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

现在我想更改该默认值。

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

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

DROP DEFAULT [dbo].[Default_Timestamp]

它给出了以下错误。

消息 3716,级别 16,状态 3,第 4 行
默认的“dbo.Default_Timestamp”无法删除,因为它绑定到一个或多个列。

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

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

任何人都可以提供一个脚本来列出与该默认值绑定的所有表和列吗?

4

4 回答 4

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

似乎更容易进入未来!当您明确命名您的约束时,如果需要,您还可以轻松找到并再次删除该约束。

于 2012-06-30T11:08:56.447 回答
2

当我在我的数据库中发现一些旧样式默认值时,我遇到了这个问题,我必须在我的数据库中大量更新uses_ansi_nulls 和uses_quoted_identifier。

这是我最终编写的代码,用于将旧样式默认值 (CREATE DEFAULT sp_BindDefault) 替换为新样式 (ALTER TABLE)。

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
于 2019-12-03T16:00:10.453 回答
1

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

默认对象的 ID,无论它是独立对象 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
于 2012-06-30T11:37:02.180 回答
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 Server 的未来版本中删除。不要在新的开发工作中使用此功能,并尽快修改当前使用此功能的应用程序。我们建议您改用 ALTER TABLE 或 CREATE TABLE 语句的 DEFAULT 关键字来创建默认定义。

当然,这也适用于sp_unbindefault

于 2012-06-30T11:07:25.277 回答