【问题标题】:How do you truncate all tables except lookup tables in a database using TSQL?如何使用 TSQL 截断数据库中除查找表之外的所有表?
【发布时间】:2015-05-21 21:02:20
【问题描述】:

在 SQL Server 2012 及更低版本中使用 TSQL 从所有表中删除除查找表数据之外的所有数据的最佳方法是什么? 我希望 TSQL 识别并排除查找表,然后为其他表创建截断表语句。

** 几乎有a similar question,但它会截断所有表格。

【问题讨论】:

  • 您认为查找表与其他表有何不同?他们的名字中有图案吗?如果您无法找到手动区分它们的方法,那么脚本不会。
  • 假设我们使用 [FK_Parent_Child] 名称标准定义了我们的约束。即 ALTER TABLE [dbo].[Parent] WITH CHECK ADD CONSTRAINT [FK_Parent_Child] FOREIGN KEY([TypeID]) REFERENCES [dbo].[Child] ([ID])
  • @TheDot 当您从数据库中删除时,我个人会很犹豫地说,说我们定义了。您仍在做出假设,并且不确定如何区分您的表。对于您需要的表,您可能还有许多其他外键。外键并不总是在查找表和真实表之间产生关系。
  • 不,这不是假设,它就是这样。我同意“外键并不总是在查找表-realt 表之间产生关系”,但在这种情况下,这正是数据库的设计方式。另外,我将我的 ID 更改为 TheStudent,对此感到抱歉。
  • 这是一个测试数据库,所以不用担心。

标签: sql-server tsql


【解决方案1】:

查找表和非查找表在技术特征上相似。只是在功能上它们是不同的。因此,不会有具体的标准来区分它们。

【讨论】:

  • 没有任何属性可以区分表的参照完整性吗?
【解决方案2】:

除非您从设计的角度设置自己能够做到这一点,例如将所有“查找”表放在“lkup”模式或类似性质的东西中,我认为没有办法做到这一点。正如有人已经提到的,查找表与其他表一样。

【讨论】:

  • 没有任何属性可以区分表的参照完整性吗?
【解决方案3】:

我会通过首先以正确的顺序删除(依赖项)来自动使用 DELETE

1) 传递表名

2) 禁用你的外键

3) 清空删除所有表

4) 重新启用它们的键。

通过这种方式,您可以使用条件控制传递要“截断”的表名。

【讨论】:

  • 你有一个工作的 TSQL 脚本,所以我可以测试它吗?
【解决方案4】:

或者那会很重要:

ALTER PROCEDURE 
up_ResetEntireDatabase 
@IncludeIdentReseed BIT, 
@IncludeDataReseed BIT 
AS 

EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' 
EXEC sp_MSForEachTable 'DELETE FROM ?'

 IF @IncludeIdentReseed = 1 
BEGIN 
EXEC sp_MSForEachTable 'DBCC CHECKIDENT (''?'' , RESEED, 1)' 
END 

EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL' 

IF @IncludeDataReseed = 1 
BEGIN 
-- Populate Core Data Table Here 
END 

GO

然后一旦准备好执行就很简单了:

EXEC up_ResetEntireDatabase 1, 1

【讨论】:

  • 当然很重要,不然我为什么还要问一个问题呢?您的脚本会删除所有表中的所有数据。我不喜欢这个主意。
  • @rrg6699 建议编辑答案并从中添加/减去,除非您的意思是每个帖子都是完全不同的答案。
  • @学生,我只是笼统地回答。您必须将代码添加到您的特定需求中
【解决方案5】:

我不确定您的意思是不是可以驱动这种情况的查找表。

构建一个简单的表,其中包含每个数据库表的名称并创建列,如果需要,您可以在执行脚本之前进行修改。

这些列可能只是告诉脚本是否截断该表或其他表的标志。

这样你(脚本)在读取表名时就会知道依赖关系。如果您在记录编号顺序中保持表顺序不变,则不需要索引。

只是另一个维护脚本。

【讨论】:

  • 不,这不是我将使用的方法。系统视图中有各种各样的信息。创建额外的表没有意义!
【解决方案6】:

因此,您希望截断具有外键的表,但单独保留引用表。应该这样做。

WITH CTE_fks
AS
(
    SELECT  obj.name AS FK_NAME,
            sch1.name AS [table_schema],
            tab1.name AS [table_name],
            col1.name AS [column],
            sch2.name AS [ref_table_schema],
            tab2.name AS [referenced_table],
            col2.name AS [referenced_column]
    FROM sys.objects obj
    INNER JOIN sys.foreign_key_columns fkc
        ON obj.object_id = fkc.constraint_object_id
    INNER JOIN sys.tables tab1
        ON tab1.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas sch1
        ON tab1.schema_id = sch1.schema_id
    INNER JOIN sys.columns col1
        ON col1.column_id = parent_column_id AND col1.object_id = tab1.object_id
    INNER JOIN sys.tables tab2
        ON tab2.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas sch2
        ON tab2.schema_id = sch2.schema_id
    INNER JOIN sys.columns col2
        ON col2.column_id = referenced_column_id AND col2.object_id = tab2.object_id
)

SELECT  'TRUNCATE TABLE ' + QUOTENAME(A.TABLE_SCHEMA) + '.' + QUOTENAME(A.table_name) + ';'
FROM INFORMATION_SCHEMA.TABLES A
LEFT JOIN CTE_fks B
ON A.TABLE_NAME = B.referenced_table
AND A.TABLE_SCHEMA = B.ref_table_schema
WHERE A.TABLE_TYPE = 'BASE TABLE'
AND A.TABLE_NAME != 'sysdiagrams'
AND B.table_name IS NULL

【讨论】:

  • 这个脚本似乎可以工作,但您能否完成该脚本,以便将数据库恢复到原始状态(启用外键),以便我可以对其进行测试。顺便说一句,我注意到上面的脚本,它还生成TRUNCATE TABLE [dbo].[sysdiagrams],我认为它不应该是选定表的一部分。
  • 您无法重新启用外键,因为查找表中没有任何内容。并且只需添加一个 where 子句来排除 sysdiagrams
  • 所有的查找表都有价值。它们不是空的,所以我们应该能够重新启用它们。这就是这个问题的全部意义所在。在从其余表中删除数据的同时保持查找表中的数据完整。
  • 哦,对不起。我在那里有点困惑。我明白你的意思,我认为你不需要禁用外键。让我编辑我的答案。
猜你喜欢
  • 2011-08-27
  • 2010-09-14
  • 1970-01-01
  • 2011-06-12
  • 2011-02-19
  • 2011-08-12
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
相关资源
最近更新 更多