【问题标题】:TSQL to clear a database's schema in sql-server?TSQL 清除 sql-server 中的数据库架构?
【发布时间】:2009-09-25 16:50:41
【问题描述】:

我想清除我的 SqlServer 实例上的数据库架构。我应该使用什么 tsql?

架构是指表、约束等。我希望结果与创建新数据库时的结果相似,但我不想实际删除并创建数据库。

原因:

对于那些好奇的人,我需要清空架构而不丢弃,因为数据库被隔离以进行单元测试。在运行我的测试之前,会保存数据库的快照。每次测试运行后,都会恢复此快照。如果我将数据库操作保持在数据库范围内,我只能确保跨单元测试的状态一致。删除/创建数据库超出了 db 的范围(它在 master 的范围内)。

在这种情况下,我需要断言当模式为空时会发生预期的事情。通过 sql 清空模式可以保持测试方法的一致性:基本上对 db 做任何你想做的事情,练习它,恢复它。

Raj More 的回答让我开始了。我希望有人可以缩短流程。

【问题讨论】:

  • 您能否详细说明为什么不能删除数据库并创建一个新数据库?数据库中是否有任何要保存的内容,例如用户主体、权限、维护计划、服务和合同等非架构绑定对象等?
  • 更新了我的问题,请参阅“为什么:”

标签: sql sql-server tsql


【解决方案1】:

我想我会分享我最终想出的东西。此脚本创建一个游标以循环遍历数据库的 INFORMATION_SCHEMA 中的表。它对掺杂外键的表进行了 3 次传递,然后是主键,最后是表本身。它基于 Raj More 的想法并考虑了 devio 的评论。

-- Helper Procedure
CREATE PROC #DropConstraints
  @tableSchema nvarchar(max),
  @tableName nvarchar(max),
  @constraintType nvarchar(20)
AS
BEGIN
  DECLARE @cName nvarchar(max);

  DECLARE constraint_cursor CURSOR FOR
    SELECT CONSTRAINT_NAME 
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    WHERE 
      CONSTRAINT_TYPE = @constraintType
      AND TABLE_NAME = @tableName
      AND TABLE_SCHEMA = @tableSchema

  OPEN constraint_cursor

  FETCH NEXT FROM constraint_cursor INTO @cName
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC ('ALTER TABLE ' + @tableSchema + '.' + @tableName + ' DROP CONSTRAINT ' + @cName);
    FETCH NEXT FROM constraint_cursor INTO @cName
  END

  CLOSE constraint_cursor
  DEALLOCATE constraint_cursor
END
GO

-- DROP DATABASE TABLES
BEGIN TRANSACTION
  DECLARE @tableSchema varchar(max), @tableName varchar(max);

  -- Setup Cursor for looping
  DECLARE table_cursor SCROLL CURSOR FOR
    SELECT TABLE_SCHEMA, TABLE_NAME 
    FROM INFORMATION_SCHEMA.TABLES

  OPEN table_cursor

  -- Drop Foreign Keys
  FETCH NEXT FROM table_cursor INTO @tableSchema, @tableName
  WHILE @@FETCH_STATUS = 0
  BEGIN  
    EXEC #DropConstraints @tableSchema, @tableName, 'FOREIGN KEY';

    FETCH NEXT FROM table_cursor INTO @tableSchema, @tableName
  END

  -- Drop Primary Keys
  FETCH FIRST FROM table_cursor INTO @tableSchema, @tableName
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC #DropConstraints @tableSchema, @tableName, 'PRIMARY KEY';

    FETCH NEXT FROM table_cursor INTO @tableSchema, @tableName
  END

  -- Drop Tables
  FETCH FIRST FROM table_cursor INTO @tableSchema, @tableName
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC ('DROP TABLE ' + @tableSchema + '.' + @tableName);

    FETCH NEXT FROM table_cursor INTO @tableSchema, @tableName
  END

  -- Cleanup
  CLOSE table_cursor
  DEALLOCATE table_cursor
COMMIT TRANSACTION
GO

【讨论】:

  • 1) DROP CONSTRAINT 是独立命令吗?我只知道这个子句是 ALTER TABLE 的一部分。 2)你需要在丢弃PK之前先丢弃FK。
  • 感谢您的评论。你是对的。我(愚蠢地)在实际测试之前发布。答案现在有了一个更正(更清晰)的版本。
  • deeno 需要更改“SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES”部分以考虑视图。
【解决方案2】:

您可以使用 INFORMATION_SCHEMA 视图集生成 SQL 脚本以删除所有对象。

您不必删除诸如索引、触发器、约束之类的项目,因为它们会在您删除它们所附加到的表时被删除。

暴力警报

现在由于关系,表格本身很棘手。

如果你用 GO 分隔每个 drop 语句,你可以继续运行脚本,直到没有错误,然后你就会有一个干净的状态。

基于反馈的非暴力破解

现在,如果先删除所有外键,那么您可以一次性删除所有表。

【讨论】:

  • 如果您碰巧有一个涉及两个或多个表的引用(外键)循环,那么简单地反复运行删除所有表脚本将不起作用。不能因为 B 引用 A 而丢弃 A,不能因为 A 引用 B 而丢弃 B。最好先查询并丢弃所有外键。
  • 我从来没有建立一个存在循环引用的数据库,所以我从没想过。我会更改答案以反映您的评论。
  • 感谢您的回答 (+1)。你帮我想出了最终的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 2014-09-18
相关资源
最近更新 更多