SQL Server DBをバックアップファイルから復元する自動化スクリプトを作成したいと思います。ただし、メインクエリには別のクエリを使用して実際に取得できるcan追加の入力が必要であるため、これをSQLで行う簡単な手順ではありません。これを1つのクエリで実行できますか?
質問 がすでにSOにあります。しかし、解決策はそれほど柔軟ではありません。 RESTORE FILELISTONLY
の定義は非常に頻繁に変更されます。それ以外の場合でも、解決策は非常に冗長に見えます。
クエリの結果を変数に保存して使用する簡単な方法はありませんか?これは、どのプログラミング言語でもケーキウォークです。
論理名を取得します。
RESTORE FILELISTONLY FROM DISK = 'D:SourceBackUpFile.bak' GO
DBを復元します。
RESTORE DATABASE DBName FROM DISK = 'D:SourceBackUpFile.bak' WITH RECOVERY MOVE 'SourceMDFLogicalName' TO 'D:TargetMDFFile.mdf', MOVE 'SourceLDFLogicalName' TO 'D:TargetLDFFile.ldf'
私は SQLServerScience.com にブログの投稿を書きました。これは、あなたが求めている詳細を取得する方法を示しており、2008以降のすべてのバージョンのSQL Serverと互換性があります。
これは、そのブログ投稿のメインコードです。
/*
This script will generate a "RESTORE DATABASE" command with the correct "MOVE" clause, etc.
By: Max Vernon
*/
SET NOCOUNT ON;
DECLARE @FileListCmd nvarchar(max);
DECLARE @RestoreCmd nvarchar(max);
DECLARE @cmd nvarchar(max);
DECLARE @BackupFile nvarchar(max);
DECLARE @DBName sysname;
DECLARE @DataPath nvarchar(260);
DECLARE @LogPath nvarchar(260);
DECLARE @Version decimal(10,2);
DECLARE @MaxLogicalNameLength int;
DECLARE @MoveFiles nvarchar(max);
SET @BackupFile = N'D:\SQLServer\MyDatabaseBackup.bak'; --source backup file
SET @DBName = N'MyDB'; --target database name
SET @DataPath = N'C:\Database\Data'; --target data path
SET @LogPath = N'C:\Database\Log'; --target log path
/* ************************************
modify nothing below this point.
************************************ */
IF RIGHT(@DataPath, 1) <> '\' SET @DataPath = @DataPath + N'\';
IF RIGHT(@LogPath, 1) <> '\' SET @LogPath = @LogPath + N'\';
SET @cmd = N'';
SET @Version = CONVERT(decimal(10,2),
CONVERT(varchar(10), SERVERPROPERTY('ProductMajorVersion'))
+ '.' +
CONVERT(varchar(10), SERVERPROPERTY('ProductMinorVersion'))
);
IF @Version IS NULL --use ProductVersion instead
BEGIN
DECLARE @sv varchar(10);
SET @sv = CONVERT(varchar(10), SERVERPROPERTY('ProductVersion'));
SET @Version = CONVERT(decimal(10,2), LEFT(@sv, CHARINDEX(N'.', @sv) + 1));
END
IF OBJECT_ID(N'tempdb..#FileList', N'U') IS NOT NULL
BEGIN
DROP TABLE #FileList;
END
CREATE TABLE #FileList
(
LogicalName sysname NOT NULL
, PhysicalName varchar(255) NOT NULL
, [Type] char(1) NOT NULL
, FileGroupName sysname NULL
, Size numeric(20,0) NOT NULL
, MaxSize numeric(20,0) NOT NULL
, FileId bigint NOT NULL
, CreateLSN numeric(25,0) NOT NULL
, DropLSN numeric(25,0) NULL
, UniqueId uniqueidentifier NOT NULL
, ReadOnlyLSN numeric(25,0) NULL
, ReadWriteLSN numeric(25,0) NULL
, BackupSizeInBytes bigint NOT NULL
, SourceBlockSize int NOT NULL
, FileGroupId int NULL
, LogGroupGUID uniqueidentifier NULL
, DifferentialBaseLSN numeric(25,0) NULL
, DifferentialBaseGUID uniqueidentifier NOT NULL
, IsReadOnly bit NOT NULL
, IsPresent bit NOT NULL
);
IF @Version >= 10.5 ALTER TABLE #FileList ADD TDEThumbprint varbinary(32) NULL;
IF @Version >= 12 ALTER TABLE #FileList ADD SnapshotURL nvarchar(360) NULL;
SET @FileListCmd = N'RESTORE FILELISTONLY FROM DISK = N''' + @BackupFile + N''';';
INSERT INTO #FileList
EXEC (@FileListCmd);
SET @MaxLogicalNameLength = COALESCE((SELECT MAX(LEN(fl.LogicalName)) FROM #FileList fl), 0);
SELECT @MoveFiles = (SELECT N', MOVE N''' + fl.LogicalName + N''' '
+ REPLICATE(N' ', @MaxLogicalNameLength - LEN(fl.LogicalName))
+ N'TO N''' + CASE WHEN fl.Type = 'L' THEN @LogPath ELSE @DataPath END
+ @DBName + N'\' + CASE WHEN fl.FileGroupName = N'PRIMARY' THEN N'System'
WHEN fl.FileGroupName IS NULL THEN N'Log'
ELSE fl.FileGroupName END
+ N'\' + fl.LogicalName + CASE WHEN fl.Type = 'L' THEN N'.log'
ELSE
CASE WHEN fl.FileGroupName = N'PRIMARY' THEN N'.mdf'
ELSE N'.ndf'
END
END + N'''
'
FROM #FileList fl
FOR XML PATH(''));
SET @MoveFiles = REPLACE(@MoveFiles, N'
', N'');
SET @MoveFiles = REPLACE(@MoveFiles, char(10), char(13) + char(10));
SET @MoveFiles = LEFT(@MoveFiles, LEN(@MoveFiles) - 2);
SET @RestoreCmd = N'RESTORE DATABASE ' + @DBName + N'
FROM DISK = N''' + @BackupFile + N'''
WITH REPLACE
, RECOVERY
, STATS = 5
' + @MoveFiles + N';
GO';
IF LEN(@RestoreCmd) > 4000
BEGIN
DECLARE @CurrentLen int;
SET @CurrentLen = 1;
WHILE @CurrentLen <= LEN(@RestoreCmd)
BEGIN
PRINT SUBSTRING(@RestoreCmd, @CurrentLen, 4000);
SET @CurrentLen = @CurrentLen + 4000;
END
RAISERROR (N'Output is chunked into 4,000 char pieces - look for errant line endings!', 14, 1);
END
ELSE
BEGIN
PRINT @RestoreCmd;
END
生成されたRESTORE DATABASE
コマンドは次のようになります。
RESTORE DATABASE MyDB
FROM DISK = N'D:\SQLServer\backups\MyDB.bak'
WITH REPLACE
, RECOVERY
, STATS = 5
, MOVE N'PRIMARY' TO N'C:\Database\Data\MyDB\system\PRIMARY'
, MOVE N'LOG' TO N'C:\Database\Log\MyDB\Log\LOG';
GO
このコードは、SQL Server 2017のLinuxバージョンでもテストされています。
あなたは尋ねました:
クエリの結果を変数に保存して使用する簡単な方法はありませんか?これは、どのプログラミング言語でも簡単なことです。
ここでの要件は、ない値を変数に追加することです。一連の異種データの内容をテーブルに抽出する必要があります。 mightは、概念的にはオブジェクトから配列をロードするのと同じです。ただし、SQL Serverでは、RESTORE HEADERONLY
コマンドのようにコマンド出力の結果を保存する唯一の方法は、まずテーブルに挿入してから、目的のテーブルから特定の値を取得することです。
this SO question から取得。これは2019年までのすべてのバージョンで機能するようです。
ただ注意してください。SQL2000以降、定義が2度変更されています。19年間に2つの変更が頻繁に行われる変更と個人的に判断することはありません。その意味では、以下のような一般的なスクリプトを使用している限り、RESTORE FILELISTONLYの使用について心配する必要はありません。
CREATE TABLE #FileListHeaders (
LogicalName nvarchar(128)
,PhysicalName nvarchar(260)
,[Type] char(1)
,FileGroupName nvarchar(128) NULL
,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 NULL
,IsReadOnly bit
,IsPresent bit
)
IF cast(cast(SERVERPROPERTY('ProductVersion') as char(4)) as float) > 9 -- Greater than SQL 2005
BEGIN
ALTER TABLE #FileListHeaders ADD TDEThumbprint varbinary(32) NULL
END
IF cast(cast(SERVERPROPERTY('ProductVersion') as char(2)) as float) > 12 -- Greater than 2014
BEGIN
ALTER TABLE #FileListHeaders ADD SnapshotURL nvarchar(360) NULL
END
INSERT INTO #FileListHeaders
EXEC ('RESTORE FILELISTONLY FROM DISK = N''BackupFileName.bak''')
SELECT * FROM #FileListHeaders
DROP TABLE #FileListHeaders
無料で利用できる dbatools または sp_restoregene を使用しないのはなぜですか?
彼らは両方ともあなたが求めていることをすることができます。