【问题标题】:How to drop SQL default constraint without knowing its name?如何在不知道其名称的情况下删除 SQL 默认约束?
【发布时间】:2010-11-28 15:55:33
【问题描述】:

在 Microsoft SQL Server 中,我知道检查列是否存在默认约束并删除默认约束的查询是:

IF EXISTS(SELECT * FROM sysconstraints
  WHERE id=OBJECT_ID('SomeTable')
  AND COL_NAME(id,colid)='ColName'
  AND OBJECTPROPERTY(constid, 'IsDefaultCnst')=1)    
ALTER TABLE SomeTable DROP CONSTRAINT DF_SomeTable_ColName

但由于数据库以前版本的拼写错误,约束的名称可能是DF_SomeTable_ColName 或DF_SmoeTable_ColName。

如何删除默认约束而不出现任何 SQL 错误?默认约束名称不会出现在 INFORMATION_SCHEMA 表中,这让事情变得有点棘手。

因此,类似“删除此表/列中的默认约束”或“删除DF_SmoeTable_ColName”之类的内容,但如果找不到,请不要给出任何错误。

【问题讨论】:

  • 我不精通SQL Server,你知道约束的名字后能重命名吗? Oracle 中的“Alter table sometable rename constraint xxx to yyy”。

标签: sql sql-server tsql


【解决方案1】:

扩展 Mitch Wheat 的代码,以下脚本将生成删除约束并动态执行它的命令。

declare @schema_name nvarchar(256)
declare @table_name nvarchar(256)
declare @col_name nvarchar(256)
declare @Command  nvarchar(1000)

set @schema_name = N'MySchema'
set @table_name = N'Department'
set @col_name = N'ModifiedDate'

select @Command = 'ALTER TABLE ' + @schema_name + '.[' + @table_name + '] DROP CONSTRAINT ' + d.name
 from sys.tables t
  join sys.default_constraints d on d.parent_object_id = t.object_id
  join sys.columns c on c.object_id = t.object_id and c.column_id = d.parent_column_id
 where t.name = @table_name
  and t.schema_id = schema_id(@schema_name)
  and c.name = @col_name

--print @Command

execute (@Command)

【讨论】:

  • 检查 stackoverflow.com/a/15786313/2049986 以查看删除表所有约束的版本
  • 我使用 sys.check_constraints ,而不是 sys.default_constraints
  • 无效 如果某些列具有 多个 默认约束或检查约束已创建,仅针对查询中的最后一个约束执行。
  • 此查询仅处理默认约束,其中每列只能有一个。处理检查约束是一个不同的问题。
  • 我已更新此答案以添加对非默认模式名称的支持。希望您不介意,如果您愿意,我可以回复并发布单独的答案。
【解决方案2】:

Rob Farley 的博文可能会有所帮助:

类似:

 declare @table_name nvarchar(256)
 declare @col_name nvarchar(256)
 set @table_name = N'Department'
 set @col_name = N'ModifiedDate'

 select t.name, c.name, d.name, d.definition
 from 
     sys.tables t
     join sys.default_constraints d on d.parent_object_id = t.object_id
     join sys.columns c on c.object_id = t.object_id
                           and c.column_id = d.parent_column_id
 where 
     t.name = @table_name
     and c.name = @col_name

【讨论】:

    【解决方案3】:

    我发现这可行并且不使用连接:

    DECLARE @ObjectName NVARCHAR(100)
    SELECT @ObjectName = OBJECT_NAME([default_object_id]) FROM SYS.COLUMNS
    WHERE [object_id] = OBJECT_ID('[tableSchema].[tableName]') AND [name] = 'columnName';
    EXEC('ALTER TABLE [tableSchema].[tableName] DROP CONSTRAINT ' + @ObjectName)
    

    只需确保 columnName 周围没有括号,因为查询正在寻找完全匹配并且如果它是 [columnName] 则不会返回任何内容。

    【讨论】:

    • 与其他任何答案不同,此答案适用于默认 [dbo] 以外的模式。
    • 我没有测试过,但是你可以尝试在它周围添加一个 WHILE (@ObjectName IS NOT NULL),在 SELECT (at)ObjectName = OBJECT_Name([default...并且只运行 EXEC('ALTER TA... if (at)ObjectName IS NOT NULL.
    • 为了使这个脚本具有幂等性,在 EXEC 命令前添加IF @ObjectName IS NOT NULL
    • 不适合我使用 CHECK 约束。 [default_object_id]) 是 0。我得到 NULL 值。
    • 甜蜜而简单,但根据微软文档,这种做事方式不会永远存在。有警告表示将在下一个版本中消失docs.microsoft.com/en-us/sql/t-sql/statements/…
    【解决方案4】:

    要删除多列的约束:

    declare @table_name nvarchar(256)
    
    declare @Command nvarchar(max) = ''
    
    set @table_name = N'ATableName'
    
    select @Command = @Command + 'ALTER TABLE ' + @table_name + ' drop constraint ' + d.name + CHAR(10)+ CHAR(13)
    from sys.tables t
    join sys.default_constraints d on d.parent_object_id = t.object_id
    join sys.columns c on c.object_id = t.object_id
         and c.column_id = d.parent_column_id
    where t.name = @table_name and c.name in ('column1','column2','column3')
    
    --print @Command
    
    execute (@Command)
    

    【讨论】:

      【解决方案5】:

      扩展解决方案(考虑表架构):

      -- Drop default contstraint for SchemaName.TableName.ColumnName
      DECLARE @schema_name NVARCHAR(256)
      DECLARE @table_name NVARCHAR(256)
      DECLARE @col_name NVARCHAR(256)
      DECLARE @Command  NVARCHAR(1000)
      
      set @schema_name = N'SchemaName'
      set @table_name = N'TableName'
      set @col_name = N'ColumnName'
      
      SELECT @Command = 'ALTER TABLE [' + @schema_name + '].[' + @table_name + '] DROP CONSTRAINT ' + d.name
       FROM sys.tables t   
        JOIN sys.default_constraints d       
         ON d.parent_object_id = t.object_id  
        JOIN sys.schemas s
              ON s.schema_id = t.schema_id
        JOIN    sys.columns c      
         ON c.object_id = t.object_id      
          AND c.column_id = d.parent_column_id
       WHERE t.name = @table_name
          AND s.name = @schema_name 
        AND c.name = @col_name
      
      EXECUTE (@Command)
      

      【讨论】:

        【解决方案6】:

        运行此命令浏览所有约束:

        exec sp_helpconstraint 'mytable' --and look under constraint_name. 
        

        它看起来像这样:DF__Mytable__Column__[ABC123]。然后你就可以放弃约束了。

        【讨论】:

        • 不适合我:exec sp_helpconstraint 'Roles2016.UsersCRM'
        • @Kiquenet 应该只是表名:exec sp_helpconstraint 'Roles2016'
        • 它只是显示外键约束。不是默认值约束
        【解决方案7】:

        删除数据库中的所有默认约束 - 对于 nvarchar(max) 阈值是安全的。

        /* WARNING: THE SAMPLE BELOW; DROPS ALL THE DEFAULT CONSTRAINTS IN A DATABASE */ 
        /* MAY 03, 2013 - BY WISEROOT  */
        declare @table_name nvarchar(128)
        declare @column_name nvarchar(128)
        declare @df_name nvarchar(128)
        declare @cmd nvarchar(128) 
        
        declare table_names cursor for 
         SELECT t.name TableName, c.name ColumnName
         FROM sys.columns c INNER JOIN
             sys.tables t ON c.object_id = t.object_id INNER JOIN
             sys.schemas s ON t.schema_id = s.schema_id
             ORDER BY T.name, c.name
        
             open table_names
        fetch next from table_names into @table_name , @column_name
        while @@fetch_status = 0
        BEGIN
        
        if exists (SELECT top(1) d.name from sys.tables t join sys.default_constraints d on d.parent_object_id = t.object_id join sys.columns c on c.object_id = t.object_id and c.column_id = d.parent_column_id where t.name = @table_name and c.name = @column_name)
        BEGIN
            SET @df_name = (SELECT top(1) d.name from sys.tables t join sys.default_constraints d on d.parent_object_id = t.object_id join sys.columns c on c.object_id = t.object_id and c.column_id = d.parent_column_id where t.name = @table_name and c.name = @column_name)
            select @cmd = 'ALTER TABLE [' + @table_name +  '] DROP CONSTRAINT [' +  @df_name + ']'
            print @cmd
            EXEC sp_executeSQL @cmd;
        END
        
          fetch next from table_names into @table_name , @column_name
        END
        
        close table_names 
        deallocate table_names
        

        【讨论】:

        • 无效 如果某些列具有 多个 默认约束或已创建检查约束,仅针对查询中的前 1 个约束 执行。
        【解决方案8】:

        我希望这对有类似问题的人有所帮助。 在ObjectExplorer 窗口中,选择您的数据库=> 表,=> 您的表=> 约束。如果客户是在创建列时定义的,您可以看到约束的默认名称,包括列名。 然后使用:

        ALTER TABLE  yourTableName DROP CONSTRAINT DF__YourTa__NewCo__47127295;
        

        (约束名称只是一个例子)

        【讨论】:

          【解决方案9】:

          以下解决方案将从表中删除特定列的默认约束

          Declare @Const NVARCHAR(256)
          
          SET @Const = (
                        SELECT TOP 1 'ALTER TABLE' + YOUR TABLE NAME +' DROP CONSTRAINT '+name
                        FROM Sys.default_constraints A
                        JOIN sysconstraints B on A.parent_object_id = B.id
                        WHERE id = OBJECT_ID('YOUR TABLE NAME')
                        AND COL_NAME(id, colid)='COLUMN NAME'
                        AND OBJECTPROPERTY(constid,'IsDefaultCnst')=1
                      )
           EXEC (@Const)
          

          【讨论】:

            【解决方案10】:

            我有一些列创建了多个默认约束,因此我创建了以下存储过程:

            CREATE PROCEDURE [dbo].[RemoveDefaultConstraints] @table_name nvarchar(256), @column_name nvarchar(256)
            AS
            BEGIN
            
                DECLARE @ObjectName NVARCHAR(100)
            
                START: --Start of loop
                SELECT 
                    @ObjectName = OBJECT_NAME([default_object_id]) 
                FROM 
                    SYS.COLUMNS
                WHERE 
                    [object_id] = OBJECT_ID(@table_name) 
                    AND [name] = @column_name;
            
                -- Don't drop the constraint unless it exists
                IF @ObjectName IS NOT NULL
                BEGIN
                    EXEC ('ALTER TABLE '+@table_name+' DROP CONSTRAINT ' + @ObjectName)
                    GOTO START; --Used to loop in case of multiple default constraints
                END
            END
            GO
            
            -- How to run the stored proc.  This removes the default constraint(s) for the enabled column on the User table.
            EXEC [dbo].[RemoveDefaultConstraints] N'[dbo].[User]', N'enabled'
            GO
            
            -- If you hate the proc, just get rid of it
            DROP PROCEDURE [dbo].[RemoveDefaultConstraints]
            GO
            

            【讨论】:

              【解决方案11】:

              对于创建了多个 default constraints or check constraints 的某些列很有用:

              修改https://stackoverflow.com/a/16359095/206730脚本

              注意:此脚本适用于 sys.check_constraints

              declare @table_name nvarchar(128)
              declare @column_name nvarchar(128)
              declare @constraint_name nvarchar(128)
              declare @constraint_definition nvarchar(512)
              
              declare @df_name nvarchar(128)
              declare @cmd nvarchar(128) 
              
              PRINT 'DROP CONSTRAINT [Roles2016.UsersCRM].Estado'
              
              declare constraints cursor for 
               select t.name TableName, c.name ColumnName, d.name ConstraintName, d.definition ConstraintDefinition
               from sys.tables t   
               join sys.check_constraints d  on d.parent_object_id = t.object_id  
               join sys.columns c  on c.object_id = t.object_id      
               and c.column_id = d.parent_column_id
               where t.name = N'Roles2016.UsersCRM' and c.name = N'Estado'
              
              open constraints
              fetch next from constraints into @table_name , @column_name, @constraint_name, @constraint_definition
              while @@fetch_status = 0
              BEGIN
                  print 'CONSTRAINT: ' + @constraint_name
                  select @cmd = 'ALTER TABLE [' + @table_name +  '] DROP CONSTRAINT [' +  @constraint_name + ']'
                  print @cmd
                  EXEC sp_executeSQL @cmd;
              
                fetch next from constraints into @table_name , @column_name, @constraint_name, @constraint_definition
              END
              
              close constraints 
              deallocate constraints
              

              【讨论】:

                【解决方案12】:

                始终在运行之前生成脚本并进行审核。脚本下方

                  select 'Alter table dbo.' + t.name + ' drop constraint '+ d.name  
                  from sys.tables t
                  join sys.default_constraints d on d.parent_object_id = t.object_id
                  join sys.columns c on c.object_id = t.object_id
                       and c.column_id = d.parent_column_id
                  where c.name in ('VersionEffectiveDate','VersionEndDate','VersionReasonDesc')
                  order by t.name
                

                【讨论】:

                  【解决方案13】:
                  declare @table_name nvarchar(100)
                  declare @col_name nvarchar(100)
                  declare @constraint nvarchar(100)
                  set @table_name = N'TableName'
                  set @col_name = N'ColumnName'
                  
                  IF EXISTS (select       c.*
                      from        sys.columns c 
                      inner join  sys.tables t on t.object_id = c.object_id
                      where       t.name = @table_name
                      and         c.name = @col_name) 
                  BEGIN
                  
                  select @constraint=d.name
                  from 
                  sys.tables t
                  join sys.default_constraints d on d.parent_object_id = t.object_id
                  join sys.columns c on c.object_id = t.object_id
                  and c.column_id = d.parent_column_id
                  where 
                  t.name = @table_name
                  and c.name = @col_name
                  
                      IF LEN(ISNULL(@constraint, '')) <> 0
                      BEGIN
                          DECLARE @sqlcmd VARCHAR(MAX)
                          SET @sqlcmd = 'ALTER TABLE ' + QUOTENAME(@table_name) + ' DROP CONSTRAINT' + 
                          QUOTENAME(@constraint);
                          EXEC (@sqlcmd);
                  
                      END
                  
                  END
                  GO
                  

                  【讨论】:

                    【解决方案14】:
                    declare @ery nvarchar(max)
                    declare @tab nvarchar(max) = 'myTable'
                    declare @qu nvarchar(max) = 'alter table '+@tab+' drop constraint '
                    
                    select @ery = (select bj.name from sys.tables as tb 
                    inner join sys.objects as bj 
                    on tb.object_id = bj.parent_object_id
                    where tb.name = @tab and bj.type = 'PK')
                    
                    exec(@qu+@ery)
                    

                    看看吧。

                    【讨论】:

                    • 即使您的代码带来了解决方案,最好还是围绕它解决问题的原因进行一些解释。
                    猜你喜欢
                    • 1970-01-01
                    • 2023-03-10
                    • 2015-03-22
                    • 1970-01-01
                    • 2011-04-26
                    • 2012-02-18
                    • 2021-01-05
                    • 2013-08-06
                    • 1970-01-01
                    相关资源
                    最近更新 更多