Search code examples
sql-serverdatabasessisautomationrestore

SSIS Restore Database with Dynamic File Name


Every week I have to restore 2 different databases. I submit a ticket to Epi support and they give me .BAK files with different dates appended to them.

Running SQL Server 2014 (on remote server), Visual Studio 19 (on local machine), and Integration Service Project.

So far, my SSIS package removes previous .BAK files from SQL Server Backup directory, moves the new ones from my Downloads folder to the SQL Server Backup directory, and deletes one of previously existing backups (I like to delete them because WITH REPLACE does not update the LAST RESTORED DATE and I like to keep those up-to-date).

I would think that I could re-use the filename and the directory from when I move the BAK files with a File System Task in order to generate the RESTORE DATABASE statement, but I am not sure how to pass those fields in SSIS.

Now, I need to EXECUTE SQL TASK to RESTORE DATABASE, but it is hard to execute this in one statement with a dynamic filename.

I have looked at many different articles and tried different things, but none have worked.

The following script is what I want to be able to run, but I get errors even when the filename is hardcoded:

RESTORE DATABASE [Insite.Commerce.horizon.Sandbox] FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\horizon-sandbox-20210412.bak'

The errors that this draws are below:

Msg 5133, Level 16, State 1, Line 2 Directory lookup for the file "d:\sqldata\\Insite.Commerce.horizon.mdf" failed with the operating system error 21(The device is not ready.).

Msg 3156, Level 16, State 3, Line 2 File 'Insite.Commerce.horizon' cannot be restored to 'd:\sqldata\\Insite.Commerce.horizon.mdf'. Use WITH MOVE to identify a valid location for the file.

Msg 5133, Level 16, State 1, Line 2 Directory lookup for the file "l:\sqllogs\\Insite.Commerce.horizon_log.ldf" failed with the operating system error 3(The system cannot find the path specified.).

Msg 3156, Level 16, State 3, Line 2 File 'Insite.Commerce.horizon_log' cannot be restored to 'l:\sqllogs\\Insite.Commerce.horizon_log.ldf'. Use WITH MOVE to identify a valid location for the file.

Msg 3119, Level 16, State 1, Line 2 Problems were identified while planning for the RESTORE statement. Previous messages provide details.

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

I am not sure how to address these errors and/or if they are even relevant because I do not know if I am going about a database restore in SSIS the right way.

Regardless, as of now, I am trying to execute the following SQL statement in SSIS in order to return the SQL statement it generates as a result or variable that can be passed to another SQL statement and then executed. See below:

DECLARE @dirPath nvarchar(500) = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\'

DECLARE @tblgetfileList TABLE
(FileName nvarchar(500)
,depth int
,isFile int)

INSERT INTO @tblgetfileList
EXEC xp_DirTree @dirPath,1,1

select 'RESTORE DATABASE [Insite.Commerce.horizon.Sandbox] FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\' + FileName + '''' from @tblgetfileList where isFile = 1 and FileName like 'horizon-sandbox-%.bak'

The output of this is: RESTORE DATABASE [Insite.Commerce.horizon.Sandbox] FROM DISK = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\horizon-sandbox-20210412.bak'

I tried storing this output as a variable and then executing it. See following script:

DECLARE @dirPath nvarchar(500) = 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\'

DECLARE @tblgetfileList TABLE
(FileName nvarchar(500)
,depth int
,isFile int)

INSERT INTO @tblgetfileList
EXEC xp_DirTree @dirPath,1,1

declare @sqltext varchar(max)

set @sqltext = '
select ''RESTORE DATABASE [Insite.Commerce.horizon.Sandbox] FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\ + FileName + '''' from @tblgetfileList where isFile = 1 and FileName like ''horizon-sandbox-%.bak''
'
exec (@sqltext)

(The quotes of @sqltext might not be perfect, but I fixed them when trying to run it)

Also, any local file directory seen in the code here I have to prepend the IPv4 Address of the remote server and then change the file directory to "C$<insert rest of directory here>". So, it looks something like "\\C$<rest of directory>". This is because I am running the SSIS package on my local machine and it is doing this work on the remote server.

Long story short, I am stuck as to what to do. I do not know the best way of going about this nor do I know how to execute upon it.

I use TSQL all the time and would consider myself intermediate, but passing variables, recursive queries, and automation/programming are some things that I DEFINITELY need to work on. So, I could be making this way more complex than it needs to be and it could be a simple fix.

Is there an easier method? Can I utilize what I have already done? I would assume that I could just write one query to do this and then execute that in SSIS Execute SQL Task or Execute TSQL Statement Task.

The end goal is just to be able to grab the name of the new BAK file and restore that database in SQL Server

Let me know if you need more information! I can edit the question as necessary.

Any and all help is welcome! Thank you in advance!


Solution

  • WITH MOVE needed to be used, but the DB name changed so all the logical filenames also had to change.

    In short, what I did was use the UX in SSMS to set-up the database restore.

    I picked my file from my device and changed the Restore To name as necessary. Then, I clicked "Script" in the top left of the Restore Database window and then clicked "New Query Editor Window".

    This scripted everything out to a new query. It included the WITH MOVEs that needed to take place and a few other settings.

    Although, how I got this to work in SSIS was I copied that new script to an Execute SQL Task in SSIS, but I added that text into another dynamic query that grabbed the filename I needed.

    Here is the full query for the restore:

    DECLARE @dirPath nvarchar(500) = '\\<IPv4 Address>\C$\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\'
    
    DECLARE @tblgetfileList TABLE
    (FileName nvarchar(500)
    ,depth int
    ,isFile int)
    
    INSERT INTO @tblgetfileList
    EXEC xp_DirTree @dirPath,1,1
    
    declare @sqltext varchar(max)
    
    select @sqltext=
        'RESTORE DATABASE [Insite.Commerce.horizon.Sandbox] FROM DISK = N''\\<IPv4 Address>\C$\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\' + FileName + '''' +
            ' WITH FILE = 1, MOVE N''Insite.Commerce.horizon'' TO N''\\<IPv4 Address>\C$\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\Insite.Commerce.horizon.Sandbox.mdf'', ' +
            'MOVE N''Insite.Commerce.horizon_log'' TO N''\\<IPv4 Address>\C$\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\Insite.Commerce.horizon.Sandbox_log.ldf'',  NOUNLOAD,  STATS = 5'
    from @tblgetfileList where isFile = 1 and FileName like 'horizon-sandbox-%.bak'
    
    exec (@sqltext)