获取SQL Server数据库并对其进行测试副本的最简单方法是什么?
我查看了一些现有主题,但不确定是否有更简单的方法。我有数据库发布者。我希望能够将两个数据库保存在同一台服务器上。
更新:我使用Microsoft SQL Server发布向导来脚本化文件,创建新数据库,添加“use db”并执行脚本。这似乎工作正常。建议不要使用附加/分离,因为如果它是全文搜索数据库或缺少日志,它会将链接留回原始位置。
答案 0 :(得分:6)
我总是只备份它然后恢复到不同的名称/文件集; How to: Restore a Database to a New Location and Name (Transact-SQL) 或者你可以创建一个空的db&使用恢复“向导”启用OVERWRITE并更改恢复文件路径。
答案 1 :(得分:2)
我只是创建数据库,然后使用SS Mgmt Studio中的“导入数据”任务来复制数据。或者,您可以备份生产数据库并将其还原到测试数据库中。
也许不是绝对最简单的方式,但相当低的戏剧性。您还可以将数据编写到文件中并将其重新播放到新数据库中 - 这需要一段时间,但它对于版本控制之类的东西很方便,而且它是人类(好的,“开发人员”) - 可读。
答案 2 :(得分:1)
取出数据库(意味着将其脱机),复制mdf文件,然后重新附加原始数据和副本。
答案 3 :(得分:0)
我经常拥有具有完全相同架构的Test和Live数据库。它们通常具有随我的开发更改状态而更改的存储过程。因此,我不能总是仅备份和还原。我写了一个查询,该查询遍历数据库中的所有表,删除了数据。然后再次循环并从实时数据库插入。 在下面,我的测试数据库称为WorkflowTest,而我的实时数据库称为Workflow,但是您只需在变量中替换数据库名称即可。只需确保连接到TEST数据库即可。
但是表名和列完全是任意的。 我多次循环,因为我不想担心外键约束。某些删除/插入操作将失败,因为它希望数据存在于另一个表中。
我发现我的全部45张左右的桌子在大约2-3个循环中被完全填充。
在插入循环中,它首先尝试通过打开IDENTITY_INSERT来检查表是否具有标识列。如果这没有失败,那么它将构建一个插入语句,其中前面的IDENTITY_INSERT为开,随后的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