0

我们将很快对产品进行一段时间的测试。该产品是一个带有 SQL Server 2008R2 后端的 Web 应用程序。

我们的数据库中有几个模式(Customer、DataEntry 和其他一些)。

我找到了在不破坏参照完整性或数据结构的情况下擦除数据库中所有数据的方法,这与我们想要做的很接近。我发现的问题是我们实际上需要一些表中的一堆数据。本质上,我们只想擦除客户模式。

我们编写了一个脚本,它将为客户加载测试数据,但是有没有办法改变我链接文章中的技术以仅针对特定模式?有没有更好的方法来清除架构中的所有数据?

4

3 回答 3

1

对我来说也是一个常见的场景。我通常编写我所谓的重置脚本,按照必要的顺序从目标表中删除所有数据以防止引用错误,然后重新设置主键。

DELETE FROM < table 1 >
DELETE FROM < table 2 >
... etc ...    
DBCC CHECKIDENT (< table 1 >, RESEED, 0)
DBCC CHECKIDENT (< table 2 >, RESEED, 0)
... etc ...

编辑

更全面地回答原始问题。要将数据保留在特定表中,您需要修改执行删除/截断的代码块,并以类似的方式修改重新设置 idents 的代码。

EXEC sp_MSForEachTable '
    IF object_id(''?'') != < table name > AND object_id(''?'') != < table name > AND ... etc ...
    BEGIN
        IF OBJECTPROPERTY(object_id(''?''), ''TableHasForeignRef'') = 1
            DELETE FROM ?
        ELSE
            TRUNCATE TABLE ?
    END
'
GO
于 2013-04-11T14:18:22.090 回答
1

只需将@schemaID 设置为您希望删除的模式的名称,剩下的就交给它了。如果你最终得到一个 FK 依赖循环,它将中断并告诉你该怎么做......

Declare @schemaID Nvarchar(256)
Set     @schemaID = 'Schema' -- Set this to the name of the schema you wish to blow away

If      Object_ID('tempdb..#tables') Is Not Null Drop Table #tables
Create  Table #tables (tID Int, SchemaName Nvarchar(256), TableName Nvarchar(256))

Insert  #tables
Select  Row_Number() Over (Order By s.name, so.name), s.name, so.name
From    sysobjects so
Join    sys.schemas s
        On  so.uid = s.schema_id
Where   so.xtype = 'u'
And     s.name = @schemaID

Declare @SQL Nvarchar(Max),
        @schema Nvarchar(256),
        @table Nvarchar(256),
        @iter Int = 1,
        @loopCatch Int = 0

While   Exists (Select  1
                From    #tables)
Begin
        Select  @schema = SchemaName,
                @table = TableName
        From    #tables
        Where   tID = @iter

        If      Exists (Select  1
                        From    sysobjects o
                        Join    sys.schemas s1
                                On  o.uid = s1.schema_id
                        Join    sysforeignkeys fk
                                On  o.id = fk.rkeyid
                        Join    sysobjects o2
                                On  fk.fkeyid = o2.id
                        Join    sys.schemas s2
                                On  o2.uid = s2.schema_id
                        Join    #tables t
                                On  o2.name = t.TableName Collate Database_Default
                                And s2.name = t.SchemaName Collate Database_Default
                        Where   o.name = @table
                        And     s1.name = @schema)
        Begin
                Update  t
                Set     tID = (Select Max(tID) From #tables) + 1
                From    #tables t
                Where   tableName = @table
                And     schemaName = @schema

                Set     @iter = @iter + 1
        End
        Else
        Begin
                Set     @Sql = 'Truncate Table [' + @schema + '].[' + @table + ']'

                Begin   Try
                        Exec    sp_executeSQL @SQL;

                        Delete  t
                        From    #tables t
                        Where   tableName = @table
                        And     schemaName = @schema

                        Set     @iter = @iter + 1
                End     Try
                Begin   Catch
                        Print @SQL

                        Update  t
                        Set     tID = (Select Max(tID) From #tables) + 1
                        From    #tables t
                        Where   tableName = @table
                        And     schemaName = @schema

                        Set     @iter = @iter + 1
                        Set     @loopCatch = @loopCatch + 1;

                        If      @loopCatch > 5
                        Begin
                                Select  'WARNING: Endless FK redundancy loop. Drop the constraints and these tables, truncate and reapply constraints manually'
                                Union   All
                                Select  '[' + SchemaName + '].[' + TableName + ']'
                                From    #tables;                

                                Break;
                        End                     
                End     Catch
        End
End
于 2013-04-11T14:41:57.773 回答
1

这是在数据库和模式上参数化的。如果没有提供模式,它将清除指定数据库中的所有数据。

通过禁用约束适当地处理具有外键引用的表。如果程序失败(通常不应该这样做),请确保在修复问题原因后成功运行它,这应确保约束检查恢复正常。

如果您在模式之间有外键,这将无法正确处理外键引用,但是,可以很容易地对其进行修改以处理此问题。

create procedure [removeData] (@database_name sysname, @schema_name sysname = null)
as
    set nocount on

    create table #tables (
        TableName varchar(900) not null primary key,
        HasFKRef bit not null
    );

    declare @sql nvarchar(4000),
            @table_name varchar(900);

    if (db_id(@database_name) is null)
        raiserror ('You must at least specify the database name', 16, 1);

    set @sql = 'select ''['' + TABLE_CATALOG + ''].['' + TABLE_SCHEMA + ''].['' + TABLE_NAME + '']'' as TableName, (case when exists(select * from [' + @database_name + '].INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc inner join [' + @database_name + '].INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc on rc.UNIQUE_CONSTRAINT_CATALOG = tc.CONSTRAINT_CATALOG and rc.UNIQUE_CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA and rc.UNIQUE_CONSTRAINT_NAME = tc.CONSTRAINT_NAME where tc.TABLE_NAME = t.TABLE_NAME) then 1 else 0 end) as HasFKRef
        from [' + @database_name + '].INFORMATION_SCHEMA.TABLES t
        where TABLE_TYPE = ''BASE TABLE'' and TABLE_SCHEMA = isnull(@schema_name, TABLE_SCHEMA)';

    insert into #tables
        exec sp_executesql @sql, N'@schema_name sysname', @schema_name;

    declare @curse cursor 
    set @curse = cursor fast_forward for
    select sql from (
        select 'alter table ' + TableName + ' nocheck constraint all' as sql, 1 as sort
        from #tables
        union all
        select 'truncate table ' + TableName, 2 as sort
        from #tables
        where HasFKRef = 0
        union all
        select 'delete from ' + TableName, 3 as sort
        from #tables
        where HasFKRef = 1
        union all
        select 'alter table ' + TableName + ' with check check constraint all', 4 as sort
        from #tables
    ) t
    order by sort, sql

    open @curse

    fetch next from @curse into @sql

    while (@@fetch_status = 0)
    begin
        exec (@sql)

        fetch next from @curse into @sql
    end

    close @curse
GO
于 2013-04-11T15:23:48.223 回答