私はSQL Serverコマンドにあまり流ではありません。
.bakファイルからデータベースを復元し、logical_dataおよびlogical_logファイルを特定のパスに移動するスクリプトが必要です。
できます:
restore filelistonly from disk='D:\backups\my_backup.bak'
これにより、列LogicalName
の結果セットが得られます。次に、復元コマンドで結果セットの論理名を使用する必要があります。
restore database my_db_name from disk='d:\backups\my_backups.bak' with file=1,
move 'logical_data_file' to 'd:\data\mydb.mdf',
move 'logical_log_file' to 'd:\data\mylog.ldf'
最初の結果セットから「移動」コマンドに提供できる変数に論理名をキャプチャするにはどうすればよいですか?
ソリューションは簡単なものかもしれないと思いますが、私はSQL Serverを初めて使用します。
完全に自動化されたT-SQLストアドプロシージャを次に示します。 3つのパラメーターを受け入れます。
\\yourserver\yourshare\backupfile.bak
または単にc:\backup.bak
)CREATE PROC [dbo].[restoreDB]
@p_strDBNameTo SYSNAME,
@p_strDBNameFrom SYSNAME,
@p_strFQNRestoreFileName VARCHAR(255)
AS
DECLARE
@v_strDBFilename VARCHAR(100),
@v_strDBLogFilename VARCHAR(100),
@v_strDBDataFile VARCHAR(100),
@v_strDBLogFile VARCHAR(100),
@v_strExecSQL NVARCHAR(1000),
@v_strExecSQL1 NVARCHAR(1000),
@v_strMoveSQL NVARCHAR(4000),
@v_strREPLACE NVARCHAR(50),
@v_strTEMP NVARCHAR(1000),
@v_strListSQL NVARCHAR(4000),
@v_strServerVersion NVARCHAR(20)
SET @v_strREPLACE = ''
IF exists (select name from sys.databases where name = @p_strDBNameTo)
SET @v_strREPLACE = ', REPLACE'
SET @v_strListSQL = ''
SET @v_strListSQL = @v_strListSQL + 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''##FILE_LIST''))'
SET @v_strListSQL = @v_strListSQL + 'BEGIN'
SET @v_strListSQL = @v_strListSQL + ' DROP TABLE ##FILE_LIST '
SET @v_strListSQL = @v_strListSQL + 'END '
SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST ('
SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),'
SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),'
SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),'
SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' FileID bigint,'
SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,'
SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,'
SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,'
SET @v_strListSQL = @v_strListSQL + ' ispresent BIT'
SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR)
IF @v_strServerVersion LIKE '10.%'
BEGIN
SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL'
--PRINT @v_strServerVersion
END
SET @v_strListSQL = @v_strListSQL + ')'
EXEC (@v_strListSQL)
INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNRestoreFileName + '''')
DECLARE curFileLIst CURSOR FOR
SELECT 'MOVE N''' + LogicalName + ''' TO N''' + replace(PhysicalName, @p_strDBNameFrom, @p_strDBNameTo) + ''''
FROM ##FILE_LIST
SET @v_strMoveSQL = ''
OPEN curFileList
FETCH NEXT FROM curFileList into @v_strTEMP
WHILE @@Fetch_Status = 0
BEGIN
SET @v_strMoveSQL = @v_strMoveSQL + @v_strTEMP + ', '
FETCH NEXT FROM curFileList into @v_strTEMP
END
CLOSE curFileList
DEALLOCATE curFileList
PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database'
-- Create the sql to kill the active database connections
SET @v_strExecSQL = ''
SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' '
FROM master.dbo.sysprocesses
WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid
EXEC (@v_strExecSQL)
PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNRestoreFileName + '" with '
PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"'
PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"'
SET @v_strExecSQL = 'RESTORE DATABASE [' + @p_strDBNameTo + ']'
SET @v_strExecSQL = @v_strExecSQL + ' FROM DISK = ''' + @p_strFQNRestoreFileName + ''''
SET @v_strExecSQL = @v_strExecSQL + ' WITH FILE = 1,'
SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL
SET @v_strExecSQL = @v_strExecSQL + ' NOREWIND, '
SET @v_strExecSQL = @v_strExecSQL + ' NOUNLOAD '
SET @v_strExecSQL = @v_strExecSQL + @v_strREPLACE
--PRINT '---------------------------'
--PRINT @v_strExecSQL
--PRINT '---------------------------'
EXEC sp_executesql @v_strExecSQL
RESTORE FILELISTONLYは、 [〜#〜] msdn [〜#〜] に記載されている結果セットを生成します。次に、この結果セットを反復して、適切なRESTORE ... MOVE ...を構築する必要があります。結果セットをキャプチャして反復する方法は、環境によって異なります。 C#アプリケーションでは、SqlDataReaderを使用します。純粋なT-SQLでは、 INSERT ... EXEC を使用します。
純粋なSQLソリューションのスケルトンは次のようになります。
declare @filelist table (LogicalName nvarchar(128), PhysicalName nvarchar(260), Type char(1), FilegroupName varchar(10), size int, MaxSize bigint, field int, createlsn bit, droplsn bit, uniqueid uniqueidentifier, readonlylsn bit, readwritelsn bit, backupsizeinbytes bigint, sourceblocksize int, filegroupid int, loggroupguid uniqueidentifier, differentialbaselsn bit, differentialbaseguid uniqueidentifier, isreadonly bit, ispresent bit, tdethumbprint varchar(5));
insert into @filelist exec sp_executesql N'restore filelistonly from disk=''D:\backups\my_backup.bak''';
set @sql = N'RESTORE database my_database from disk ''D:\backups\my_backup.bak'' with ';
select @sql = @sql + N' move ' + LogicalName + N' to ' udf_localFilePath(PhysicalName) + N','
from @filelist;
set @sql = substring(@sql, 1, len(@sql)-1); -- remove last ','
exec sp_executesql @sql;
これは実際に動作するコードではなく、アイデアを得るためのものです。 @sqlの非標準のassign-inside-query構造の代わりにカーソルを使用することもできます
RESTORE FILELISTONLY
の結果セットの列のリストは、SQL Serverのバージョンによって異なることに注意してください。正しいリストについては、ターゲットバージョンの仕様を参照してください。
を使用して
参照として、私はこれを思いついた..そして、私はそれが機能すると思う(複数のファイルでのバックアップについてはテストされていない)
DECLARE @FileList TABLE
(
LogicalName nvarchar(128) NOT NULL,
PhysicalName nvarchar(260) NOT NULL,
Type char(1) NOT NULL,
FileGroupName nvarchar(120) NULL,
Size numeric(20, 0) NOT NULL,
MaxSize numeric(20, 0) NOT NULL,
FileID bigint NULL,
CreateLSN numeric(25,0) NULL,
DropLSN numeric(25,0) NULL,
UniqueID uniqueidentifier NULL,
ReadOnlyLSN numeric(25,0) NULL ,
ReadWriteLSN numeric(25,0) NULL,
BackupSizeInBytes bigint NULL,
SourceBlockSize int NULL,
FileGroupID int NULL,
LogGroupGUID uniqueidentifier NULL,
DifferentialBaseLSN numeric(25,0)NULL,
DifferentialBaseGUID uniqueidentifier NULL,
IsReadOnly bit NULL,
IsPresent bit NULL,
TDEThumbprint varbinary(32) NULL
);
declare @RestoreStatement nvarchar(max), @BackupFile nvarchar(max);
set @BackupFile = 'D:\mybackup.bak'
SET @RestoreStatement = N'RESTORE FILELISTONLY
FROM DISK=N''' + @BackupFile + ''''
INSERT INTO @FileList
EXEC(@RestoreStatement);
declare @logical_data nvarchar(max), @logical_log nvarchar(max);
set @logical_data = (select LogicalName from @FileList where Type = 'D' and FileID = 1)
set @logical_log = (select LogicalName from @FileList where Type = 'L' and FileID = 2)
/*
Automate restore w/o needing to know the logical file names.
Specify destination database name, database backup source filename
and .MDF, .LDF and .NDF directories.
I do nightly automated database restores,
and I've been using this code for about a month.
Works for sql server 2008, might work for 2005.
Created by wtm 5/27/2010
*/
-- BEGIN - MODIFY THIS CODE - create a blank db
if not exists(select * from master.sys.databases where [name]='sc')
begin
create database sc
end
go
-- END - MODIFY THIS CODE - create a blank db
declare @strDatabase varchar(130)='sc' -- MODIFY THIS LINE - db name
declare @strBackupFile varchar(500)='c:\docs\db-backups\sc.bak' -- MODIFY THIS LINE - source db backup file
declare @strRestoreMDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for main files
declare @strRestoreLDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for tlog files
declare @strRestoreNDFFilesTo varchar(500)='c:\docs\sqldata\' -- MODIFY THIS LINE - destination restore directory for non-main files
-- other variables used
declare @strSQL nvarchar(max)
declare @strOriginalPhysicalName varchar(150)
declare @strPhysicalName varchar(150)
declare @strLogicalName varchar(150)
declare @intReturn int
-- begin restoring
begin try
drop table #tmpFilelist
end try
begin catch
end catch
create table #tmpFilelist (
LogicalName varchar(64), PhysicalName varchar(130), [Type] varchar(1), FileGroupName varchar(64), Size decimal(20, 0)
,MaxSize decimal(25, 0), FileID bigint, CreateLSN decimal(25,0), DropLSN decimal(25,0), UniqueID uniqueidentifier
,ReadOnlyLSN decimal(25,0), ReadWriteLSN decimal(25,0), BackSizeInBytes decimal(25,0), SourceBlockSize int
,filegroupid int, loggroupguid uniqueidentifier, differentialbaseLSN decimal(25,0), differentialbaseGUID uniqueidentifier
,isreadonly bit, ispresent bit, TDEThumbpr decimal
)
if not exists(select * from sc.sys.tables) or exists(select * from sc.sys.tables where [name]='not-an-original-table') -- MODIFY THIS LINE - business logic to see if we need to restore the database at all
begin
print 'Restoring '+@strDatabase+' db ...'
use master
exec msdb.dbo.sp_delete_database_backuphistory @database_name = @strDatabase
use [master]
exec('alter database '+@strDatabase+' set single_user with rollback immediate')
use [master]
exec('drop database '+@strDatabase)
insert into #tmpFilelist
exec('restore filelistonly from disk = '''+@strBackupFile+'''')
set @strSQL='restore database ['+@strDatabase+'] from disk='''+@strBackupFile+''' with '
set @strSQL=@strSQL+ 'file=1 '
set @strSQL=@strSQL+ ',nounload '
set @strSQL=@strSQL+ ',replace '
set @strSQL=@strSQL+ ',stats=10 ' -- show restore status every 10%
while exists(select * from #tmpFilelist)
begin
select top 1 @strOriginalPhysicalName=PhysicalName, @strLogicalName=LogicalName from #tmpFilelist
set @strPhysicalName=@strOriginalPhysicalName
set @strPhysicalName=reverse(@strPhysicalName)
set @strPhysicalName=left(@strPhysicalName, charindex('\', @strPhysicalName)-1)
set @strPhysicalName=reverse(@strPhysicalName)
set @strPhysicalName=replace(@strPhysicalName, '.', '_'+@strDatabase+'.')
if @strPhysicalName like '%.mdf'
set @strPhysicalName=@strRestoreMDFFilesTo+@strPhysicalName
else if @strPhysicalName like '%.ldf'
set @strPhysicalName=@strRestoreLDFFilesTo+@strPhysicalName
else
set @strPhysicalName=@strRestoreNDFFilesTo+@strPhysicalName
set @strSQL=@strSQL+ ',move '''+@strLogicalName+''' to '''+@strPhysicalName+''' '
delete from #tmpFilelist where PhysicalName=@strOriginalPhysicalName
end
execute @intReturn=sp_executesql @strSQL
end
私は同じ問題を抱えていましたが、私の環境には多くのバックアップファイル(高速バックアップ)があり、カスタムの場所に復元する必要がありました。このクエリは、最新の完全バックアップ情報を取得し、指定したパスに復元します。 SQL 2005/2008でテスト済み。
SET NOCOUNT ON
Declare @BackupFiles varchar(500), @data_file_path VARCHAR(512), @log_file_path VARCHAR(512), @RestoreFileList varchar(2000), @RestoreStatement varchar(3000), @MoveFiles varchar(2000), @DBName varchar(150)
DECLARE @filelist TABLE (LogicalName NVARCHAR(128) NOT NULL, PhysicalName NVARCHAR(260) NOT NULL, [Type] CHAR(1) NOT NULL, FileGroupName NVARCHAR(120) NULL, Size NUMERIC(20, 0) NOT NULL, MaxSize NUMERIC(20, 0) NOT NULL, FileID BIGINT NULL, CreateLSN NUMERIC(25,0) NULL, DropLSN NUMERIC(25,0) NULL, UniqueID UNIQUEIDENTIFIER NULL, ReadOnlyLSN NUMERIC(25,0) NULL , ReadWriteLSN NUMERIC(25,0) NULL, BackupSizeInBytes BIGINT NULL, SourceBlockSize INT NULL, FileGroupID INT NULL, LogGroupGUID UNIQUEIDENTIFIER NULL, DfferentialBaseLSN NUMERIC(25,0)NULL, DifferentialBaseGUID UNIQUEIDENTIFIER NULL, IsReadOnly BIT NULL, IsPresent BIT NULL, TDEThumbprint VARBINARY(32) NULL)
SET @data_file_path = 'E:\SQLData\'
SET @log_file_path = 'E:\SQLLog\'
SET @DBName = 'Adventureworks'
--Get last full backup:
SELECT @BackupFiles=Coalesce(@BackupFiles + ',', '') + 'DISK = N'''+physical_device_name+''''
FROM msdb..backupset S
JOIN msdb..backupmediafamily M ON M.media_set_id=S.media_set_id
WHERE backup_set_id = ( SELECT max(backup_set_id)
FROM msdb..backupset S
JOIN msdb..backupmediafamily M ON M.media_set_id=S.media_set_id
WHERE S.database_name = @DBName and Type = 'D')
SELECT @RestoreFileList= 'RESTORE FILELISTONLY FROM ' + @BackupFiles + ' WITH FILE = 1 '
IF (@@microsoftversion / 0x1000000) & 0xff >= 10 --TDE capability
Begin
INSERT into @filelist (LogicalName,PhysicalName,Type,FileGroupName,Size,MaxSize,FileID,CreateLSN,DropLSN,UniqueID,ReadOnlyLSN,ReadWriteLSN,BackupSizeInBytes,SourceBlockSize,FileGroupID,LogGroupGUID,DfferentialBaseLSN,DifferentialBaseGUID,IsReadOnly,IsPresent,TDEThumbprint)
EXEC (@RestoreFileList)
End
Else
Begin
INSERT into @filelist (LogicalName,PhysicalName,Type,FileGroupName,Size,MaxSize,FileID,CreateLSN,DropLSN,UniqueID,ReadOnlyLSN,ReadWriteLSN,BackupSizeInBytes,SourceBlockSize,FileGroupID,LogGroupGUID,DfferentialBaseLSN,DifferentialBaseGUID,IsReadOnly,IsPresent)
EXEC (@RestoreFileList)
End
--next version, do a count on filename, any >1 put in alternate data/log location.
SELECT @MoveFiles=Coalesce(@MoveFiles + ',' , '') + 'MOVE N''' + LogicalName + ''' to N''' +
Case When type = 'D' Then @data_file_path+Right(physicalname, charindex('\',reverse(physicalname),1)-1)
when type = 'L' Then @log_file_path+Right(physicalname, charindex('\',reverse(physicalname),1)-1)
Else 'Full Text - code not complete'
END
+''''
From @filelist
SELECT @RestoreStatement='RESTORE DATABASE [AuctionMain] FROM ' + @BackupFiles + ' WITH FILE = 1, ' + @MoveFiles + ', NOUNLOAD, REPLACE, STATS = 20'
Print @RestoreStatement
Exec(@RestoreStatement)
どのバージョンにもSQL 2000は含まれていません。これはすべてのバージョンで機能します。
use master
--
-- check SQL Server version
DECLARE @sql_ver int;
CREATE TABLE #tmp_sql_ver
(
[Index] int,
[Name] nvarchar(100),
[iVal] int,
[cVal] nvarchar(100)
)
INSERT INTO #tmp_sql_ver EXEC('xp_msver ProductVersion');
IF (SELECT cast(cVal as char(2)) FROM #tmp_sql_ver) = '8.'
SET @sql_ver = 8;
ELSE
SET @sql_ver = 9;
DROP TABLE #tmp_sql_ver;
--
-- get mdf/ldf names
DECLARE @mdf_name varchar(50)
DECLARE @ldf_name varchar(50)
DECLARE @RestoreFileListOnly_columns varchar(2000)
IF (@sql_ver = 8)
BEGIN
SET @RestoreFileListOnly_columns = '
LogicalName nvarchar(128),
PhysicalName nvarchar(260),
[Type] char(1),
FileGroupName nvarchar(128),
[Size] numeric(20,0),
[MaxSize] numeric(20,0),
'
END
ELSE
BEGIN
SET @RestoreFileListOnly_columns = '
LogicalName nvarchar(128),
PhysicalName nvarchar(260),
[Type] char(1),
FileGroupName nvarchar(128),
[Size] numeric(20,0),
[MaxSize] numeric(20,0),
FileID bigint,
CreateLSN numeric(25,0),
DropLSN numeric(25,0) NULL,
UniqueID uniqueidentifier,
ReadOnlyLSN numeric(25,0) NULL,
ReadWriteLSN numeric(25,0) NULL,
BackupSizeInBytes bigint,
SourceBlockSize int,
FileGroupID int,
LogGroupGUID uniqueidentifier NULL,
DifferentialBaseLSN numeric(25,0) NULL,
DifferentialBaseGUID uniqueidentifier,
IsReadOnly bit,
IsPresent bit
'
DECLARE @tmp_ver NVARCHAR(20)
SELECT @tmp_ver = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR)
IF @tmp_ver LIKE '1[01].%'
BEGIN
SET @RestoreFileListOnly_columns = @RestoreFileListOnly_columns + ', TDEThumbpr DECIMAL'
END
END
IF EXISTS (SELECT [table_name] FROM information_schema.tables WHERE [table_name] = 'tmp_RestoreFileListOnly')
BEGIN
DROP TABLE [tmp_RestoreFileListOnly];
END
EXEC ('CREATE TABLE tmp_RestoreFileListOnly ('+@RestoreFileListOnly_columns+');');
INSERT INTO tmp_RestoreFileListOnly EXEC('RESTORE FILELISTONLY FROM DISK = ''' + @bkpfile + '''')
PRINT 'RESTORE FILELISTONLY FROM DISK = ''' + @bkpfile + ''''
--IF @@ROWCOUNT <> 2 RETURN
SELECT @mdf_name = LogicalName FROM tmp_RestoreFileListOnly WHERE Type = 'D'
SELECT @ldf_name = LogicalName FROM tmp_RestoreFileListOnly WHERE Type = 'L'
DROP TABLE tmp_RestoreFileListOnly
これが役立つかもしれません。単一の場所から復元された複数のデータベースバックアップに対して設定する必要がある最小限の変数を使用して、クライアント用のスクリプトを作成したかった。動的なSQLの使用は避けようとしましたが、それはすべて面倒だと思うからです。
-- Use VARCHAR as the restore statement doesn't like NVARCHAR
DECLARE @data_file_path VARCHAR(512), @log_file_path VARCHAR(512), @backup_path VARCHAR(512),
@backup_extension VARCHAR(4), @mdf_extension VARCHAR(4), @ldf_extension VARCHAR(4)
-- ** VARIABLES THAT MUST BE SET **--
SET @data_file_path = 'E:\DataPath\'
SET @log_file_path = 'F:\LogPath'
SET @backup_path = 'B:\BackUpPath'
-- **----------------------------**--
SET @backup_extension = '.bak'
SET @mdf_extension = '.mdf'
SET @ldf_extension = '.ldf'
DECLARE @DATABASES_TO_RESTORE TABLE (rownum int IDENTITY (1, 1) PRIMARY KEY NOT NULL, backup_name VARCHAR(64), restore_as VARCHAR(64))
-- ** Declare the Databases to be Restored ** --
INSERT INTO @DATABASES_TO_RESTORE
SELECT 'Intranet', 'Intranet_Test'
UNION
SELECT 'TestAudit', 'TestAudit_Test'
-- ** -------------------------------------** --
DECLARE @max_rows INT, @row_count INT
SET @row_count = 1
SELECT @max_rows=count(*) FROM @DATABASES_TO_RESTORE
WHILE @row_count <= @max_rows
BEGIN
DECLARE @backup_name VARCHAR(32), @restore_as VARCHAR(32), @logical_data_name VARCHAR(64), @logical_log_name VARCHAR(64),
@data_file_full_path VARCHAR(512), @log_file_full_path VARCHAR(512), @full_backup_path VARCHAR(MAX)
SELECT @backup_name = backup_name, @restore_as = restore_as FROM @DATABASES_TO_RESTORE WHERE rownum = @row_count
SET @full_backup_path = @backup_path + @backup_name + @backup_extension
DECLARE @filelist TABLE (LogicalName NVARCHAR(128) NOT NULL, PhysicalName NVARCHAR(260) NOT NULL, [Type] CHAR(1) NOT NULL, FileGroupName NVARCHAR(120) NULL, Size NUMERIC(20, 0) NOT NULL, MaxSize NUMERIC(20, 0) NOT NULL, FileID BIGINT NULL, CreateLSN NUMERIC(25,0) NULL, DropLSN NUMERIC(25,0) NULL, UniqueID UNIQUEIDENTIFIER NULL, ReadOnlyLSN NUMERIC(25,0) NULL , ReadWriteLSN NUMERIC(25,0) NULL, BackupSizeInBytes BIGINT NULL, SourceBlockSize INT NULL, FileGroupID INT NULL, LogGroupGUID UNIQUEIDENTIFIER NULL, DfferentialBaseLSN NUMERIC(25,0)NULL, DifferentialBaseGUID UNIQUEIDENTIFIER NULL, IsReadOnly BIT NULL, IsPresent BIT NULL, TDEThumbprint VARBINARY(32) NULL)
INSERT into @filelist
EXEC ('RESTORE FilelistOnly FROM DISK = ''' + @full_backup_path + '''')
IF @@ROWCOUNT = 2
BEGIN
SELECT @logical_data_name = LogicalName FROM @filelist WHERE [Type] = 'D'
SELECT @logical_log_name = LogicalName FROM @filelist WHERE [Type] = 'L'
SET @data_file_full_path = @data_file_path + @restore_as + @mdf_extension
SET @log_file_full_path = @log_file_path + @restore_as + @ldf_extension
RESTORE DATABASE @restore_as
FROM DISK = @full_backup_path
WITH
FILE = 1,
MOVE @logical_data_name
TO @data_file_full_path,
MOVE @logical_log_name
TO @log_file_full_path
END
ELSE
PRINT 'CANNOT RESTORE DATABASE ' + @restore_as + ' THE BACKUP CONTAINS MORE THAN 1 BACKUP SET'
SELECT @row_count = @row_count + 1
END
さらに別の修正/実装。これが私の2セントです。上記のMevdivenのスクリプトを変更して、現在のデータベースデータディレクトリにファイルを復元するようにしました。バックアップファイルで定義された場所を使用したくないという問題があります。
最初のマスターファイルで使用されるデータディレクトリを取得します
SELECT top(1) @v_strRestorePath = physical_name FROM sys.master_files
そして、それを宛先データパスとして使用します。
また、## FILE_LISTテーブルがぶらぶらしていることもわかったため、最後近くにドロップしました。
余分な-'は、SQLがスタックオーバーフローで適切に見えるようにするためのものです。
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('[dbo].[restoreDB]') IS NOT NULL
DROP PROC [dbo].[restoreDB]
GO
CREATE PROC [dbo].[restoreDB]
@p_strDBNameTo SYSNAME,
@p_strDBNameFrom SYSNAME,
@p_strFQNRestoreFileName VARCHAR(255)
AS
DECLARE
@v_strDBFilename VARCHAR(100),
@v_strDBLogFilename VARCHAR(100),
@v_strDBDataFile VARCHAR(100),
@v_strDBLogFile VARCHAR(100),
@v_strExecSQL NVARCHAR(1000),
@v_strExecSQL1 NVARCHAR(1000),
@v_strMoveSQL NVARCHAR(4000),
@v_strREPLACE NVARCHAR(50),
@v_strTEMP NVARCHAR(1000),
@v_strListSQL NVARCHAR(4000),
@v_strServerVersion NVARCHAR(20),
@v_strRestorePath varchar(500)
SET @v_strREPLACE = ''
IF exists (select name from sys.databases where name = @p_strDBNameTo)
SET @v_strREPLACE = ', REPLACE'
SET @v_strListSQL = ''
SET @v_strListSQL = @v_strListSQL + 'IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''##FILE_LIST''))'
SET @v_strListSQL = @v_strListSQL + 'BEGIN'
SET @v_strListSQL = @v_strListSQL + ' DROP TABLE ##FILE_LIST '
SET @v_strListSQL = @v_strListSQL + 'END '
SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST ('
SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),'
SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),'
SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),'
SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' FileID bigint,'
SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,'
SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,'
SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,'
SET @v_strListSQL = @v_strListSQL + ' ispresent BIT'
SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR)
IF @v_strServerVersion LIKE '10.%'
BEGIN
SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL'
--PRINT @v_strServerVersion
END
SET @v_strListSQL = @v_strListSQL + ')'
EXEC (@v_strListSQL)
-- We want to get the current data path from this server as the backup file paths may not be the same on the server
-- especially wehen switching between Express/Standard instances
SELECT top(1) @v_strRestorePath = physical_name FROM sys.master_files;
set @v_strRestorePath = REPLACE(@v_strRestorePath, RIGHT(@v_strRestorePath, CHARINDEX('\', REVERSE(@v_strRestorePath))-1),'')
--print @v_strRestorePath --'
INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNRestoreFileName + '''')
-- want to see whats in the fillist?
--SELECT * FROM ##FILE_LIST
DECLARE curFileLIst CURSOR FOR
-- Here we restore each file to the current server restore path. Right(...) grabs the file name from the back up
SELECT 'MOVE N''' + LogicalName + ''' TO N''' + @v_strRestorePath + Replace(RIGHT(PhysicalName, CHARINDEX('\', REVERSE(PhysicalName))-1),@p_strDBNameFrom, @p_strDBNameTo) + '''' --'
FROM ##FILE_LIST
SET @v_strMoveSQL = ''
OPEN curFileList
FETCH NEXT FROM curFileList into @v_strTEMP
WHILE @@Fetch_Status = 0
BEGIN
SET @v_strMoveSQL = @v_strMoveSQL + @v_strTEMP + ', '
FETCH NEXT FROM curFileList into @v_strTEMP
END
CLOSE curFileList
DEALLOCATE curFileList
PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database'
-- Create the sql to kill the active database connections
SET @v_strExecSQL = ''
SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' '
FROM master.dbo.sysprocesses
WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid
EXEC (@v_strExecSQL)
PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNRestoreFileName + '" with '
PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"'
PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"'
SET @v_strExecSQL = 'RESTORE DATABASE [' + @p_strDBNameTo + ']'
SET @v_strExecSQL = @v_strExecSQL + ' FROM DISK = ''' + @p_strFQNRestoreFileName + ''''
SET @v_strExecSQL = @v_strExecSQL + ' WITH FILE = 1,'
SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL
SET @v_strExecSQL = @v_strExecSQL + ' NOREWIND, '
SET @v_strExecSQL = @v_strExecSQL + ' NOUNLOAD '
SET @v_strExecSQL = @v_strExecSQL + @v_strREPLACE
--PRINT '---------------------------'
--PRINT @v_strExecSQL
--PRINT '---------------------------'
--For Some reason the file list hangs when I was debugging remove it.
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '##FILE_LIST'))
BEGIN
DROP TABLE ##FILE_LIST
END
EXEC sp_executesql @v_strExecSQLter
これが誰かにも役立つことを願っています!
ここで見つかった回答に基づいて新しいバージョンを作成しました。 SQL Serverの最新バージョンで動作するはずです。
バックアップの場所が提供されると、バックアップからデータベースが復元され、MDFおよびLDFファイルが指定された場所に移動されます。
declare @databaseName nvarchar(max);
declare @backUpDiskLocation nvarchar(max);
declare @physicalMDFLocation nvarchar(max);
declare @physicalLDFLocation nvarchar(max);
set @databaseName = '[<DB_Name>]';
set @backUpDiskLocation = 'C:\SQL-BACKUP\<backUP-Name>.bak';
set @physicalMDFLocation = 'C:\SQL\SQLData\<MDF-Name>.mdf';
set @physicalLDFLocation = 'C:\SQL\SQL-LOG\<LDF-Name_log>.LDF'
if (DB_ID(@databaseName)) is not null
Begin
DECLARE @kill varchar(8000); SET @kill = '';
SELECT @kill = @kill + 'kill ' + CONVERT(varchar(5), spid) + ';'
FROM master..sysprocesses
WHERE dbid = DB_ID(@databaseName)
EXEC(@kill);
DECLARE @Alter nvarchar(max); SET @Alter = 'ALTER DATABASE ' + @databaseName +' SET offline WITH Rollback Immediate'
EXEC (@Alter)
END
declare @sql nvarchar(max)
set @sql = N'restore filelistonly from disk=''' + @backUpDiskLocation +'''';
select @sql
create table #filelist (LogicalName nvarchar(128), PhysicalName nvarchar(260), Type char(1), FilegroupName varchar(10), size bigint, MaxSize bigint, field int, createlsn bit, droplsn bit, uniqueid uniqueidentifier, readonlylsn bit, readwritelsn bit, backupsizeinbytes bigint, sourceblocksize int, filegroupid int, loggroupguid uniqueidentifier, differentialbaselsn bit, differentialbaseguid uniqueidentifier, isreadonly bit, ispresent bit, tdethumbprint varchar(5), SnapshotUrl nvarchar(128));
insert into #filelist exec sp_executesql @sql;
ALTER TABLE #filelist add id int identity(1,1)
update #filelist set PhysicalName = @physicalMDFLocation where [id]= 1
update #filelist set PhysicalName = @physicalLDFLocation where [id]= 2
select * from #filelist
set @sql = N'RESTORE database '+ @databaseName +' from disk = '''+ @backUpDiskLocation +''' with replace, ';
select @sql
select @sql = @sql + N' move ''' + LogicalName + N''' to ''' + PhysicalName + N''',' from #filelist;
set @sql = substring(@sql, 1, len(@sql)-1); -- remove last ','
select @sql
exec sp_executesql @sql;
drop table #filelist
特定のソリューションの下にコメントを追加する方法がわかりませんが、上記のMevdivenが提供するソリューションを実装しました...
私の環境(Server 08 r2)のドロップテーブルにはわずかな問題があります。正常にドロップするには、オブジェクトIDを使用するようにこれを変更する必要がありました。
また、バックアップファイル内の多数のパーティションが原因で問題が発生したため、文字列をnvarchar(MAX)に変更する必要がありました。
また、データベースを別のディレクトリに復元する機能を追加しました(開発環境と製品環境ではパスが異なるため)
CREATE PROC [dbo].[restoreDB]
@p_strDBNameTo SYSNAME,
@p_strDBNameFrom SYSNAME,
@p_strBackupDirectory VARCHAR(255),
@p_strRestoreDirectory VARCHAR(255),
@p_strFQNBackupFileName VARCHAR(255)
AS
DECLARE
@v_strDBFilename VARCHAR(200),
@v_strDBLogFilename VARCHAR(200),
@v_strDBDataFile VARCHAR(200),
@v_strDBLogFile VARCHAR(200),
@v_strExecSQL NVARCHAR(MAX),
@v_strMoveSQL NVARCHAR(MAX),
@v_strREPLACE NVARCHAR(50),
@v_strTEMP NVARCHAR(1000),
@v_strListSQL NVARCHAR(4000),
@v_strServerVersion NVARCHAR(20)
SET @v_strREPLACE = ''
IF exists (select name from sys.databases where name = @p_strDBNameTo)
SET @v_strREPLACE = ', REPLACE'
SET @v_strListSQL = ''
SET @v_strListSQL = @v_strListSQL + 'IF OBJECT_ID(''tempdb..##FILE_LIST'') IS NOT NULL DROP TABLE ##FILE_LIST '
SET @v_strListSQL = @v_strListSQL + 'CREATE TABLE ##FILE_LIST ('
SET @v_strListSQL = @v_strListSQL + ' LogicalName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' PhysicalName VARCHAR(130),'
SET @v_strListSQL = @v_strListSQL + ' [Type] VARCHAR(1),'
SET @v_strListSQL = @v_strListSQL + ' FileGroupName VARCHAR(64),'
SET @v_strListSQL = @v_strListSQL + ' Size DECIMAL(20, 0),'
SET @v_strListSQL = @v_strListSQL + ' MaxSize DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' FileID bigint,'
SET @v_strListSQL = @v_strListSQL + ' CreateLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' DropLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' UniqueID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' ReadOnlyLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' ReadWriteLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' BackupSizeInBytes DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' SourceBlockSize INT,'
SET @v_strListSQL = @v_strListSQL + ' filegroupid INT,'
SET @v_strListSQL = @v_strListSQL + ' loggroupguid UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseLSN DECIMAL(25,0),'
SET @v_strListSQL = @v_strListSQL + ' differentialbaseGUID UNIQUEIDENTIFIER,'
SET @v_strListSQL = @v_strListSQL + ' isreadonly BIT,'
SET @v_strListSQL = @v_strListSQL + ' ispresent BIT'
SELECT @v_strServerVersion = CAST(SERVERPROPERTY ('PRODUCTVERSION') AS NVARCHAR)
IF @v_strServerVersion LIKE '10.%'
BEGIN
SET @v_strListSQL = @v_strListSQL + ', TDEThumbpr DECIMAL'
--PRINT @v_strServerVersion
END
SET @v_strListSQL = @v_strListSQL + ')'
EXEC (@v_strListSQL)
INSERT INTO ##FILE_LIST EXEC ('RESTORE FILELISTONLY FROM DISK = ''' + @p_strFQNBackupFileName + '''')
DECLARE curFileLIst CURSOR FOR
SELECT 'MOVE N''' + LogicalName + ''' TO N''' + replace(replace(PhysicalName, @p_strDBNameFrom, @p_strDBNameTo), @p_strBackupDirectory, @p_strRestoreDirectory) + ''''
FROM ##FILE_LIST
SET @v_strMoveSQL = cast('' as nvarchar(max))
OPEN curFileList
FETCH NEXT FROM curFileList into @v_strTEMP
WHILE @@Fetch_Status = 0
BEGIN
SET @v_strMoveSQL = @v_strMoveSQL + cast(@v_strTEMP as nvarchar(max)) + cast(', ' as nvarchar(max))
FETCH NEXT FROM curFileList into @v_strTEMP
END
CLOSE curFileList
DEALLOCATE curFileList
PRINT 'Killing active connections to the "' + @p_strDBNameTo + '" database'
-- Create the sql to kill the active database connections
SET @v_strExecSQL = ''
SELECT @v_strExecSQL = @v_strExecSQL + 'kill ' + CONVERT(CHAR(10), spid) + ' '
FROM master.dbo.sysprocesses
WHERE DB_NAME(dbid) = @p_strDBNameTo AND DBID <> 0 AND spid <> @@spid
EXEC (@v_strExecSQL)
PRINT 'Restoring "' + @p_strDBNameTo + '" database from "' + @p_strFQNBackupFileName + '" with '
PRINT ' data file "' + @v_strDBDataFile + '" located at "' + @v_strDBFilename + '"'
PRINT ' log file "' + @v_strDBLogFile + '" located at "' + @v_strDBLogFilename + '"'
SET @v_strExecSQL = cast('RESTORE DATABASE [' as nvarchar(max)) + cast(@p_strDBNameTo as nvarchar(max)) + cast(']' as nvarchar(max))
SET @v_strExecSQL = @v_strExecSQL + cast(' FROM DISK = ''' as nvarchar(max)) + cast(@p_strFQNBackupFileName as nvarchar(max)) + cast('''' as nvarchar(max))
SET @v_strExecSQL = @v_strExecSQL + cast(' WITH FILE = 1,' as nvarchar(max))
SET @v_strExecSQL = @v_strExecSQL + @v_strMoveSQL
SET @v_strExecSQL = @v_strExecSQL + cast(' NOREWIND, ' as nvarchar(max))
SET @v_strExecSQL = @v_strExecSQL + cast(' NOUNLOAD ' as nvarchar(max))
SET @v_strExecSQL = @v_strExecSQL + cast(@v_strREPLACE as nvarchar(max))
--If want to print string need to do in sections due to limitation of print string length
PRINT 'Exec string: ' +cast(len(@v_strExecSQL) as nvarchar(max))+ ' ***:'
PRINT substring(@v_strExecSQL,0,3999)
PRINT substring(@v_strExecSQL,4000,7999)
PRINT substring(@v_strExecSQL,8000,11999)
PRINT substring(@v_strExecSQL,12000,15999)
PRINT substring(@v_strExecSQL,16000,19999)
PRINT substring(@v_strExecSQL,20000,23999)
PRINT substring(@v_strExecSQL,24000,27999)
PRINT substring(@v_strExecSQL,28000,31999)
PRINT substring(@v_strExecSQL,32000,35999)
EXEC sp_executesql @v_strExecSQL
GO