我在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”,因为它绑定到一个或多个列。
由于默认值已被少数表使用,因此我无法删除并重新创建新表。
我知道在重新创建它之前,我需要取消绑定此默认表中的所有表。
是否有人可以提供脚本来列出与该默认值绑定的所有表和列?
答案 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