有没有办法避免脚本还原时出现MOVE错误?

时间:2019-06-14 17:41:58

标签: sql-server vb.net tsql

我已经搜索了一段时间这个问题,如果找不到解决方案,我将无法解决。

每周我们都会从客户那里获得新的数据库。我开发了一种工具来还原我们自己的数据库,以使所有数据库与客户端数据库保持一致。 该工具适用于某些数据库,但是在其他数据库上,由于日志文件,我会遇到一些错误。

我的还原数据库脚本如下

USE [master] 
ALTER DATABASE[MyDataBase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE 
RESTORE DATABASE[MyDataBase] 
FROM  DISK = N'MyDataBase.bak' 
WITH NOUNLOAD, 
REPLACE, STATS = 5 
ALTER DATABASE[MyDataBase] SET MULTI_USER

我知道如果使用MOVE命令可以解决问题,那是我无法事先知道文件,这意味着我无法真正编写任何自定义代码来还原数据库。

深入研究发现,我可以使用以下命令从数据库中打印所有日志文件

SELECT 
  DB_NAME([database_id]) [database_name]
, [file_id]
, [type_desc] [file_type]
, [name] [logical_name]
, [physical_name]
FROM sys.[master_files]
WHERE [database_id] IN (DB_ID('MyDataBase'))
ORDER BY [type], DB_NAME([database_id]);

但是这里显示的文件与我收到错误提示的文件完全不同。

要注意的另一重要事项是,如果我还原数据库,然后尝试通过tsql还原,则可以进行还原,但是我有一个Server Agent Job重命名文件以保持文件干净,并且在运行后无法再次还原数据库,并给出与手动还原之前相同的错误。

我不知道我要实现的目标是否可以实现,以及如何实现。如果有人可以给我一些灯光,那就太好了

1 个答案:

答案 0 :(得分:2)

RESTORE FILELISTONLY会告诉您文件,然后您可以从中建立RESTORE ... WITH MOVE:

EG

--backup database a to disk='c:\temp\a.bak'

declare @fn nvarchar(255) = 'c:\temp\a.bak';
declare @sql nvarchar(max) = concat('restore filelistonly from disk=''',@fn,'''');
declare @targetFolder nvarchar(max) = 'c:\temp\customer_123';
declare @dbname sysname = 'a_123';

declare @t table
(
LogicalName nvarchar(128),--,   --Logical name of the file.
PhysicalName    nvarchar(260),--    Physical or operating-system name of the file.
Type    char(1),--  The type of file, one of:
FileGroupName   nvarchar(128) NULL, --  Name of the filegroup that contains the file.
Size    numeric(20,0),--    Current size in bytes.
MaxSize numeric(20,0),--    Maximum allowed size in bytes.
FileID  bigint,--   File identifier, unique within the database.
CreateLSN   numeric(25,0),--    Log sequence number at which the file was created.
DropLSN numeric(25,0) NULL, --  The log sequence number at which the file was dropped. If the file has not been dropped, this value is NULL.
UniqueID    uniqueidentifier,-- Globally unique identifier of the file.
ReadOnlyLSN numeric(25,0) NULL, --  Log sequence number at which the filegroup containing the file changed from read-write to read-only (the most recent change),--.
ReadWriteLSN    numeric(25,0) NULL, --  Log sequence number at which the filegroup containing the file changed from read-only to read-write (the most recent change),--.
BackupSizeInBytes   bigint, --  Size of the backup for this file in bytes.
SourceBlockSize int, -- Block size of the physical device containing the file in bytes (not the backup device),--.
FileGroupID int,-- ID of the filegroup.
LogGroupGUID    uniqueidentifier NULL, --   NULL.
DifferentialBaseLSN numeric(25,0) NULL, --  For differential backups, changes with log sequence numbers greater than or equal to DifferentialBaseLSN are included in the differential 
DifferentialBaseGUID    uniqueidentifier NULL, --   For differential backups, the unique identifier of the differential base.
IsReadOnly  bit,--  1 = The file is read-only.
IsPresent   bit,--  1 = The file is present in the backup.
TDEThumbprint   varbinary(32) NULL, --  Shows the thumbprint of the Database Encryption Key. The encryptor thumbprint is a SHA-1 hash of the certificate with which the key is encrypted. For information about database encryption, see Transparent Data Encryption (TDE),--.
SnapshotURL nvarchar(360)-- NULL    The URL for the Azure snapshot of the database file contained in the FILE_SNAPSHOT backup. Returns NULL if no FILE_SNAPSHOT backup.
);
insert into @t
exec (@sql);


with q as 
(
select concat('restore database ',@dbname,' from disk=''',@fn,''' with ') l
union all
select concat('
move ''',LogicalName,''' to ''', @targetFolder, '\', LogicalName, case [type] when 'D' then '.mdf' when 'L' then '.ldf' else null end, ''' , ')
from @t 
union all
select 'RECOVERY, STATS = 10'
)
select @sql = STRING_AGG(l,'
')
from q;


print (@sql);
exec (@sql );