【问题标题】:Truncate Table With Foreign Key用外键截断表
【发布时间】:2014-01-07 15:40:03
【问题描述】:

我有一个包含 1000 多个表的数据库。我正在创建新的空白设置。为此,我必须截断所有表,但有些表我不想截断,所以我在表上创建并将名称存储在表中。

    ----------- Create hardcode table ----------------------
    Create table TblHardCodeTableNotToTruncate(TableName varchar(100))
    go
    insert into TblHardCodeTableNotToTruncate
    select 'TblHardCodeTableNotToTruncate'
    go

    ---- insert the table names which dont wish to truncate ------------
Insert into TblHardCodeTableNotToTruncate
select 'TblAccount'
go
Insert into TblHardCodeTableNotToTruncate
select 'TblCity'
go

等,以下是我用来截断除这些插入表之外的所有表的查询

------------------------- Truncate all the tables except the tables specified in the Hardcode table -------------------------

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'

GO

EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'

GO

DECLARE @TBLTEMP TABLE(TABLENAME VARCHAR(100))
insert into @TBLTEMP
select name from sysobjects where xtype = 'U'

delete from @TBLTEMP where tablename in (
select tablename from TblHardCodeTableNotToTruncate)

DECLARE @SQLQUERY VARCHAR(MAX) =''
DECLARE @INTCNT INT = 1

DECLARE @TABLENAME VARCHAR(100) =''


WHILE (SELECT COUNT(*) FROM @TBLTEMP) > 0
BEGIN


            select  top 1 @TABLENAME = TABLENAME from @TBLTEMP
            SET @SQLQUERY = 'Truncate table ' + @TABLENAME
            EXEC(@SQLQUERY)
            PRINT @SQLQUERY
    DELETE FROM @TBLTEMP WHERE TABLENAME = @TABLENAME   
END
go

EXEC sp_MSForEachTable  'ALTER TABLE ? CHECK CONSTRAINT ALL'

GO

EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'
go

但我得到错误外键引用错误。我知道我需要在做之前放弃约束。但是有什么办法可以做到这一点,因为我不能删除然后截断并每次添加这么多表。我们可以在下面编写任何独特的脚本,如果存在则删除约束,截断表并将删除的约束再次添加到表中。

【问题讨论】:

  • 我想你正在寻找这个脚本来启用、禁用、删除和重新创建基于主键表的 FK:mssqltips.com/sqlservertip/1376/…
  • 我是空白的你能告诉我我可以在我的while循环中写什么

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


【解决方案1】:

恐怕如果不放弃约束就无法做到这一点, 您可以编写一个代码来提取表的约束并删除它们,这很简单。

创建一个临时表并使用此代码获取表约束,并注意 sysconstraints.status 必须为 1 或 3 才能获取外键和主键:

Select  SysObjects.[Name] As "Constraint Name",
        Tabls.[Name] as "Table Name",
        Cols.[Name] As "Column Name"
From SysObjects Inner Join 
(Select [Name],[ID] From SysObjects) As Tabls
On Tabls.[ID] = Sysobjects.[Parent_Obj] 
Inner Join sysconstraints On sysconstraints.Constid = Sysobjects.[ID] 
Inner Join SysColumns Cols On Cols.[ColID] = sysconstraints.[ColID] 
And Cols.[ID] = Tabls.[ID]
where sysconstraints.status in (1, 3)
order by [Tabls].[Name] 

你必须在截断后重新创建这些约束,这也很简单,但我不会做你所有的工作:)

【讨论】:

  • 这是一项非常复杂的工作,我过去做过(当然我现在没有代码了),因为您必须存储要创建副本的所有信息。为什么不能只通过现有数据生成的脚本创建数据库?它将重新创建结构。使用专门的软件。改用删除(注意日志大小:))
  • 恐怖 - 请检查您的数据库可能不是关系数据库,换句话说,您没有任何主键或外键...
  • Mathese - 我明白了你的想法,但我认为 Jean 想要一个他可以在未来开发的代码,而不仅仅是删除数据/截断表一次......
  • sysconstraints.status 需要与 3 进行二进制与运算以仅检查主键和外键位:where sysconstraints.status & 3 in (1, 3)
【解决方案2】:

即使所有表都是空的并且您禁用所有约束,截断也会因为 FK 的存在而失败。你真的必须放弃它。

您可以创建一个脚本来自动化它(截断所有删除和重新创建 FK 的表) 我在这里找到了一个(谨慎使用) http://www.sqlservercentral.com/scripts/Development/62892/

此外,如果您只想创建“一揽子”数据库,您可以导出脚本以创建所有对象,然后只填充您需要的少数(域?)表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-04
    • 2011-07-24
    • 2014-05-21
    • 2013-10-06
    • 2016-07-28
    • 2016-10-25
    相关资源
    最近更新 更多