【问题标题】:Easiest way to make copy SQL Server DB to test DB?复制 SQL Server DB 以测试 DB 的最简单方法?
【发布时间】:2010-04-20 16:16:15
【问题描述】:

获取 SQL Server 数据库并制作它的测试副本的最简单方法是什么?

我浏览了一些现有的主题,但不确定是否有更简单的方法。我有数据库发布者。我希望能够将两个数据库保存在同一台服务器上,可能。

更新:我使用 Microsoft SQL Server Publishing Wizard 编写脚本到文件,创建新数据库,添加“use db”,然后执行脚本。这似乎工作正常。不建议使用附加/分离,因为如果它是全文搜索数据库或日志丢失,它会将链接返回到原始位置。

【问题讨论】:

    标签: sql-server database sql-server-2008


    【解决方案1】:

    我总是只是备份它然后恢复到不同的名称/文件集; How to: Restore a Database to a New Location and Name (Transact-SQL) 或者您可以创建一个空数据库并使用恢复“向导”启用 OVERWRITE 并更改恢复文件路径。

    【讨论】:

    • 这显然不适用于跨版本。从 SQL 2012 复制到 2008 时,我失败了。
    • iirc 您不能使用任何方法从新版本转到旧版本,因为不支持降级
    • 有点糟糕,如果你问我的话。有什么选择?将 sql 转储到文件太慢,导出导入向导已损坏,复制数据库向导在 Express 版本上不起作用。
    • 文档链接已旧。根据较新的docs,SSMS 似乎是现在要走的路。
    【解决方案2】:

    我只是创建数据库,然后使用 SS Mgmt Studio 中的“导入数据”任务复制数据。或者您可以备份生产数据库并将其恢复到测试数据库。

    也许不是最简单的方法,但相当低调。您还可以将数据编写到一个文件中并将其回放到一个新的数据库中——这需要一段时间,但它对于版本控制之类的东西很方便,而且它是人类(嗯,“开发者”)可读的。

    【讨论】:

    • 我尝试了“导入数据”选项,但对于视图,它似乎导入了行而不是视图。资源消耗,不是很有用:-/
    【解决方案3】:

    分离数据库(意味着使其脱机),复制 mdf 文件,然后重新附加原始文件和副本。

    【讨论】:

    • @Joel 如果我这样做,它会显示 SQL Server 中的位置与我的原始文件相同。我将它复制到了一个新目录,但是当我重新连接 SQl Server Management Studio 时,显示的路径与我的原始文件相同。
    【解决方案4】:

    我经常拥有具有完全相同架构的测试和实时数据库。他们通常具有根据我的开发更改状态而更改的存储过程。所以我不能总是只备份和恢复。我写了一个查询,遍历数据库中的所有表,删除数据。然后再次循环并从实时数据库中插入。 在下面,我的测试数据库称为 WorkflowTest,我的 live 称为 Workflow,但您可以只替换变量中的数据库名称。只需确保连接到 TEST 数据库即可。

    但是表名和列是完全任意的。 我循环多次,因为我不想担心外键约束。一些删除/插入将失败,因为它期望数据存在于另一个表中。

    我发现我的所有 45 个左右的表都在大约 2-3 个循环中完全重新填充。

    在插入循环期间,它首先通过尝试打开 IDENTITY_INSERT 检查表是否具有标识列。如果这没有失败,那么它将构建一个插入语句,其前面的 IDENTITY_INSERT On 和后面的 IDENTITY_INSERT 关闭。它必须在同一个 EXEC 语句中完成,因为 EXEC 中的命令在执行后会超出范围。

    事后看来,我想我可以将我所有的测试存储过程脚本化为 alter 语句,从实时数据库的备份中恢复测试数据库,然后执行我的 alter 语句。但我发现用户安全设置无法正确恢复,所以有时这也很麻烦。

                -- Gets a list of all tables in the Test database
                -- first loops through them and deletes all records.
                --   if it encounters an error, it does not remove that table from #tablesNeedingCopy so it will try again.
                --   this is because we don't know the order to delete and may encounter foreign key constraints.
                --   It usually deletes all records from all tables after 2 or so loops.
    
                -- the 2nd step is nearly identical, but instead it inserts the data
                Declare @CopyToDatabase varchar(100)
                declare @CopyFromDatabase varchar(100)
    
                set @CopyToDatabase = 'WorkflowTest'
                set @CopyFromDatabase = 'Workflow'
    
                use WorkflowTest -- [Connect to Database that you want to copy to]
    
    
                DECLARE @sqlCommand varchar(max)
                declare @columnNames varchar(max)
                DECLARE @tableName as NVARCHAR(100);
                DECLARE @tableNameCursor as CURSOR;
    
                create table #tablesNeedingCopy
                (
                    Table_Name varchar(100)
                )
    
    
                insert into #tablesNeedingCopy
                (Table_Name)
                SELECT TABLE_NAME
                FROM INFORMATION_SCHEMA.TABLES 
                WHERE TABLE_TYPE = 'BASE TABLE' 
                    and Table_Name not like 'sys%'
    
                declare @hasTableError as char(1)
                declare @remainingTableCount int
                declare @loopControl int
                set @loopControl = 0
    
                select @remainingTableCount = count(*)
                from #tablesNeedingCopy
    
                while (@remainingTableCount > 0 And @loopControl < 10)
                begin
    
    
                    set @loopControl = @loopControl + 1
    
                    SET @tableNameCursor = CURSOR FOR
                    SELECT TABLE_NAME
                    FROM #tablesNeedingCopy
    
    
    
    
                    OPEN @tableNameCursor;
                    FETCH NEXT FROM @tableNameCursor INTO @tableName;
    
                    WHILE @@FETCH_STATUS = 0
                    BEGIN
    
                    set @hasTableError = 'N'
    
    
                    SET @sqlCommand = 'Delete from ' + @tableName
                    print @sqlCommand
                    begin try
                        exec (@sqlCommand)
                    end try
                    begin catch 
                        set @hasTableError = 'Y'
                        print ERROR_MESSAGE()
                    end catch
    
    
    
                    if (@hasTableError = 'N')
                    begin
                        -- otherwise leave the table in
                        delete from #tablesNeedingCopy
                        where Table_Name = @tableName
                    end
    
                    FETCH NEXT FROM @tableNameCursor INTO @tableName;
                    END
    
                    CLOSE @tableNameCursor;
                    DEALLOCATE @tableNameCursor;
    
                    select @remainingTableCount = count(*)
                    from #tablesNeedingCopy
    
                end -- end while
    
    
                select @remainingTableCount = count(*)
                    from #tablesNeedingCopy
    
    
                if (@remainingTableCount > 0)
                begin
                select Table_Name as DeleteTableNames 
                from #tablesNeedingCopy
                end
    
                delete from  #tablesNeedingCopy
    
                -------
    
    
                insert into #tablesNeedingCopy
                (Table_Name)
                SELECT TABLE_NAME
                FROM INFORMATION_SCHEMA.TABLES 
                WHERE TABLE_TYPE = 'BASE TABLE' 
                    and Table_Name not like 'sys%'
    
                declare @hasIdentityColumn as char(1)
                set @loopControl = 0
    
    
                select @remainingTableCount = count(*)
                from #tablesNeedingCopy
    
                while (@remainingTableCount > 0 And @loopControl < 10)
                begin
    
                    set @loopControl = @loopControl + 1
    
                    SET @tableNameCursor = CURSOR FOR
                    SELECT TABLE_NAME
                    from #tablesNeedingCopy
    
    
    
    
                    OPEN @tableNameCursor;
                    FETCH NEXT FROM @tableNameCursor INTO @tableName;
    
                    WHILE @@FETCH_STATUS = 0
                    BEGIN
    
                    set @hasTableError = 'N'
                    set @hasIdentityColumn = 'Y'
    
                    SET @sqlCommand = 'SET IDENTITY_INSERT ' + @CopyToDatabase + '.dbo.' + @tableName + ' ON;' -- Database to copy to
                    begin try
                        print @sqlCommand
                        exec (@sqlCommand)
                    end try
                    begin catch 
                    --print  ERROR_MESSAGE() 
                    set @hasIdentityColumn = 'N'
                    end catch
    
    
                    if (@hasTableError = 'N')
                    begin
                        SELECT  top 1 @columnNames =
                            STUFF((SELECT N', ' + Column_Name 
                                    FROM INFORMATION_SCHEMA.COLUMNS AS t2 
                                    WHERE t2.TABLE_NAME=t.TABLE_NAME 
                                    FOR XML PATH,TYPE).value(N'.','nvarchar(max)'),1,2,'')
                        FROM INFORMATION_SCHEMA.COLUMNS t
                        WHERE TABLE_NAME = @tableName
                        order by ORDINAL_POSITION
    
    
                        set @sqlCommand = 'Insert into ' + @CopyToDatabase + '.dbo.' + @tableName + ' (' + @columnNames + ') select ' + @columnNames + ' from ' + @CopyFromDatabase + '.dbo.' + @tableName 
    
                        if (@hasIdentityColumn = 'Y')
                        begin
                        set @sqlCommand = 'SET IDENTITY_INSERT ' + @CopyToDatabase + '.dbo.' + @tableName + ' ON; ' + @sqlCommand + ' SET IDENTITY_INSERT ' + @CopyToDatabase + '.dbo.' + @tableName + ' OFF;'
                        end
                        print @sqlCommand
                        begin try
                            exec (@sqlCommand)
                        end try
                        begin catch
                            set @hasTableError = 'Y'
                            print ERROR_MESSAGE()
                        end catch
                    end
    
    
                    if (@hasTableError = 'N')
                    begin
                        -- otherwise leave the table in
                        delete from #tablesNeedingCopy
                        where Table_Name = @tableName
                    end
    
                    FETCH NEXT FROM @tableNameCursor INTO @tableName;
                    END
    
                    CLOSE @tableNameCursor;
                    DEALLOCATE @tableNameCursor;
    
                    select @remainingTableCount = count(*)
                    from #tablesNeedingCopy
    
                end -- end while
    
                select @remainingTableCount = count(*)
                    from #tablesNeedingCopy
    
    
                if (@remainingTableCount > 0)
                begin
                select Table_Name as InsertTableNames 
                from #tablesNeedingCopy
                end
    
                drop table #tablesNeedingCopy
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      • 2016-11-24
      • 2021-12-05
      相关资源
      最近更新 更多