在不知道逻辑文件名的情况下恢复 SQL 服务器数据库

Restore SQL Server database without knowing the Logical File Names

我有一个用于恢复数据库的批处理文件。这些 .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
Logical file 'Customer' is not part of database 'MyDatabase'. Use RESTORE FILELISTONLY to list the logical file names.

Msg 3013, Level 16, State 1, Server XXXXXX, Line 1
RESTORE DATABASE is terminating abnormally.

如果我尝试在没有 MOVE 子句的情况下进行还原,还原会尝试将文件 "back" 放在它们最初来自的位置——就像包含其他人的主目录的路径:

Msg 5133, Level 16, State 1, Server XXXXXX, Line 1
Directory lookup for the file "C:\TEMP\Not.Me\WidgetsRUs.mdf" failed with the operating system error 2(The system cannot find the file specified.).

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

有什么想法吗?

按照建议,使用 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

基于@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
)