在不知道逻辑文件名的情况下还原SQL Server数据库

时间:2018-03-22 16:47:25

标签: sql-server batch-file restore

我有一个用于恢复数据库的批处理文件。这些是我们部门以外的其他人创建的.bak文件,数据库名称可预测不可预测,因为它们通常以我们的各种客户命名。

SET servername=XXXXXX
SET mssqldir=C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL
SET datapath=%mssqldir%\DATA
SET dbfile=%~1    

SqlCmd -E -S %servername% -Q "RESTORE DATABASE [MyDatabase] FROM DISK = N'%dbfile%' WITH FILE = 1, MOVE 'Customer' TO N'%datapath%\Customer.mdf', MOVE 'Customer_log' TO '%datapath%\Customer.ldf', NOUNLOAD, STATS = 10"

如上所述,上述命令的问题是Customer并非总是Customer

所以,当我运行它时,我会得到类似的东西:

  

Msg 3234,Level 16,State 2,Server XXXXXX,Line 1
  逻辑文件'客户'不属于数据库' MyDatabase'。使用RESTORE FILELISTONLY列出逻辑文件名。

     

消息3013,级别16,状态1,服务器XXXXXX,行1   RESTORE DATABASE异常终止。

如果我尝试在没有MOVE子句的情况下进行恢复,则恢复会尝试将文件放回"返回"它们最初来自哪里 - 就像包含其他人的主目录的路径一样:

  

消息5133,级别16,状态1,服务器XXXXXX,行1   目录查找文件" C:\ TEMP \ Not.Me \ WidgetsRUs.mdf"操作系统错误2失败(系统找不到指定的文件。)。

我希望有一种神奇的方式可以说:MOVE '*.*' TO '"%datapath%'

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

根据建议,使用 RESTORE FILELISTONLY 获取数据库和日志名称

@echo off
SetLocal EnableDelayedExpansion EnableExtensions

set "servername=XXXXXX"
set "mssqldir=C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL"
set "datapath=%mssqldir%\DATA"
set "dbfile=%~1"
set "command=" & set "restore=" 
set "database=" & set "databaselog="

set "command=%command%DECLARE @Table TABLE (LogicalName varchar(128),[PhysicalName] varchar(128),[Type] varchar,[FileGroupName] varchar(128),"
set "command=%command%[Size] varchar(128),[MaxSize] varchar(128),[FileId] varchar(128),[CreateLSN] varchar(128),[DropLSN] varchar(128),"
set "command=%command%[UniqueId] varchar(128),[ReadOnlyLSN] varchar(128),[ReadWriteLSN] varchar(128),[BackupSizeInBytes] varchar(128),"
set "command=%command%[SourceBlockSize] varchar(128),[FileGroupId] varchar(128),[LogGroupGUID] varchar(128),[DifferentialBaseLSN] varchar(128),"
set "command=%command%[DifferentialBaseGUID] varchar(128),[IsReadOnly] varchar(128),[IsPresent] varchar(128),[TDEThumbprint] varchar(128));"
set "command=%command%DECLARE @LogicalNameData varchar(128),@LogicalNameLog varchar(128);"
set "command=%command%INSERT INTO @table EXEC('RESTORE FILELISTONLY FROM DISK='''+'%dbfile%'+''' ');"
set "command=%command%SET @LogicalNameData=(SELECT LogicalName FROM @Table WHERE Type='D');"
set "command=%command%SET @LogicalNameLog=(SELECT LogicalName FROM @Table WHERE Type='L');"
set "command=%command%SELECT @LogicalNameData,@LogicalNameLog;"

set "restore=%restore%RESTORE DATABASE [MyDatabase] FROM DISK = N'%dbfile%' WITH FILE = 1, "
set "restore=%restore%MOVE '%database%' TO N'%datapath%\Customer.mdf', "
set "restore=%restore%MOVE '%databaselog%' TO '%datapath%\Customer.ldf', "
set "restore=%restore%NOUNLOAD, STATS = 10"

for /f "skip=2 usebackq tokens=1,2* delims= " %%a in (`sqlcmd -h-1 -b -E -S %servername% -Q "%command%"`) do if not defined database set "database=%%a" & set "databaselog=%%b"

echo %database%
echo %databaselog%
if not exist "%datapath%" md "%datapath%">nul
sqlcmd -E -S %servername% -Q "%restore%"

EndLocal
exit/B 1

答案 1 :(得分:0)

基于@Elzooilogico的回答。我认为我只是包含我的最终版本,以防其他人为其他人添加一些清晰度。

@ECHO OFF

SET servername=XXXXXXX
SET mssqldir=C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL
SET datapath=%mssqldir%\DATA
SET dbfile=%mssqldir%\Backup\default.bak


SET isDefault=true
IF NOT "%~1"=="" (
    SET dbfile=%~1
    SET isDefault=false
)

ECHO Target file: %dbfile%

ECHO. 
ECHO Closing connections ...
SqlCmd -E -S %servername% -Q "ALTER DATABASE MyDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE"

ECHO. 
ECHO Removing old database ...
SqlCmd -E -S %servername% -Q "DROP DATABASE MyDatabase"

SET command=
SET command=%command%DECLARE @FileListTable TABLE (
SET command=%command%  [LogicalName]           NVARCHAR(128),
SET command=%command%  [PhysicalName]          NVARCHAR(260),
SET command=%command%  [Type]                  CHAR(1),
SET command=%command%  [FileGroupName]         NVARCHAR(128),
SET command=%command%  [Size]                  NUMERIC(20,0),
SET command=%command%  [MaxSize]               NUMERIC(20,0),
SET command=%command%  [FileId]                BIGINT,
SET command=%command%  [CreateLSN]             NUMERIC(25,0),
SET command=%command%  [DropLSN]               NUMERIC(25,0),
SET command=%command%  [UniqueId]              UNIQUEIDENTIFIER,
SET command=%command%  [ReadOnlyLSN]           NUMERIC(25,0),
SET command=%command%  [ReadWriteLSN]          NUMERIC(25,0),
SET command=%command%  [BackupSizeInBytes]     BIGINT,
SET command=%command%  [SourceBlockSize]       INT,
SET command=%command%  [FileGroupID]           INT,
SET command=%command%  [LogGroupGUID]          UNIQUEIDENTIFIER,
SET command=%command%  [DifferentialBaseLSN]   NUMERIC(25,0),
SET command=%command%  [DifferentialBaseGUID]  UNIQUEIDENTIFIER,
SET command=%command%  [IsReadOnly]            BIT,
SET command=%command%  [IsPresent]             BIT,
SET command=%command%  [TDEThumbprint]         VARBINARY(32),
SET command=%command%  [SnapshotUrl]           NVARCHAR(360)
SET command=%command%);

SET command=%command%INSERT INTO @FileListTable EXEC('RESTORE FILELISTONLY FROM DISK = ''%dbfile%''');
SET command=%command%SELECT [LogicalName], [Type] FROM @fileListTable;
SET command=%command%DECLARE @LogicalNameData varchar(128), @LogicalNameLog varchar(128);
SET command=%command%SET @LogicalNameData=(SELECT LogicalName FROM @FileListTable WHERE Type='D');
SET command=%command%SET @LogicalNameLog=(SELECT LogicalName FROM @FileListTable WHERE Type='L');

SET command=%command%RESTORE DATABASE [MyDatabase] FROM DISK = N'%dbfile%' WITH FILE = 1, 
SET command=%command% MOVE @LogicalNameData TO N'%datapath%\MyDatabase.mdf', 
SET command=%command% MOVE @LogicalNameLog TO N'%datapath%\MyDatabase.ldf', 
SET command=%command% NOUNLOAD, STATS = 10;

ECHO. 
ECHO Resotring database from file ...
SqlCmd -E -S %servername% -Q "%command%"


ECHO. 
ECHO Changing Owner ...
SqlCmd -E -S %servername% -d "MyDatabase" -Q "EXEC sp_changedbowner 'sa'"

ECHO. 
ECHO.

IF "%isDefault%"=="false" ( 
    PAUSE
    REM timeout /t 3
)