This script restores a database without having to know the logical file names. It also lets you place the MDF, LDF and NDF files wherever you want them. I mainly use it to run a nightly restore on my local machine. The line with "business logic" does a quick test to see if the database has been changed at all. There's no need to restore a database if it hasn't been changed, so the "business logic" line is how I tell it to skip the restore step.
/* Automate restore w/o needing to know the logical file names. */
-- BEGIN - MODIFY THIS CODE - create a blank db
if not exists(select * from master.sys.databases where [name]='DBNAME')
begin
create database DBNAME
end
go
-- END - MODIFY THIS CODE - create a blank db
declare @strDatabase varchar(130)='DBNAME' -- MODIFY THIS LINE - db name
declare @strBackupFile varchar(500)='e:\docs\db-backups\dbname_backup_file.bak' -- MODIFY THIS LINE - source db backup file
declare @strRestoreMDFFilesTo varchar(500)='e:\docs\sqldata\default\' -- MODIFY THIS LINE - destination restore directory for main files
declare @strRestoreLDFFilesTo varchar(500)='c:\docs\sqldata\default\' -- MODIFY THIS LINE - destination restore directory for tlog files
declare @strRestoreNDFFilesTo varchar(500)='c:\docs\sqldata\default\' -- MODIFY THIS LINE - destination restore directory for non-main files
-- other variables used
declare @strSQL nvarchar(max)
declare @strOriginalPhysicalName varchar(150)
declare @strPhysicalName varchar(150)
declare @strLogicalName varchar(150)
declare @intReturn int
-- begin restoring
begin try
drop table #tmpFilelist
end try
begin catch
end catch
create table #tmpFilelist (
LogicalName varchar(64), PhysicalName varchar(130), [Type] varchar(1), FileGroupName varchar(64), Size decimal(20, 0)
,MaxSize decimal(25, 0), FileID bigint, CreateLSN decimal(25,0), DropLSN decimal(25,0), UniqueID uniqueidentifier
,ReadOnlyLSN decimal(25,0), ReadWriteLSN decimal(25,0), BackSizeInBytes decimal(25,0), SourceBlockSize int
,filegroupid int, loggroupguid uniqueidentifier, differentialbaseLSN decimal(25,0), differentialbaseGUID uniqueidentifier
,isreadonly bit, ispresent bit, TDEThumbpr decimal
)
if not exists(select * from DBNAME.sys.tables) -- MODIFY THIS LINE - business logic to see if we need to restore the database at all
begin
print 'Restoring '+@strDatabase+' db ...'
use master
exec msdb.dbo.sp_delete_database_backuphistory @database_name = @strDatabase
use [master]
exec('alter database '+@strDatabase+' set single_user with rollback immediate')
use [master]
exec('drop database '+@strDatabase)
insert into #tmpFilelist
exec('restore filelistonly from disk = '''+@strBackupFile+'''')
set @strSQL='restore database ['+@strDatabase+'] from disk='''+@strBackupFile+''' with '
set @strSQL=@strSQL+ 'file=1 '
set @strSQL=@strSQL+ ',nounload '
set @strSQL=@strSQL+ ',replace '
set @strSQL=@strSQL+ ',stats=10 '
while exists(select * from #tmpFilelist)
begin
select top 1 @strOriginalPhysicalName=PhysicalName, @strLogicalName=LogicalName from #tmpFilelist
set @strPhysicalName=@strOriginalPhysicalName
set @strPhysicalName=reverse(@strPhysicalName)
set @strPhysicalName=left(@strPhysicalName, charindex('\', @strPhysicalName)-1)
set @strPhysicalName=reverse(@strPhysicalName)
set @strPhysicalName=replace(@strPhysicalName, '.', '_'+@strDatabase+'.')
if @strPhysicalName like '%.mdf'
set @strPhysicalName=@strRestoreMDFFilesTo+@strPhysicalName
else if @strPhysicalName like '%.ldf'
set @strPhysicalName=@strRestoreLDFFilesTo+@strPhysicalName
else
set @strPhysicalName=@strRestoreNDFFilesTo+@strPhysicalName
set @strSQL=@strSQL+ ',move '''+@strLogicalName+''' to '''+@strPhysicalName+''' '
delete from #tmpFilelist where PhysicalName=@strOriginalPhysicalName
end
execute @intReturn=sp_executesql @strSQL
end
I love SQL Server. As of Oct. 2010, I am also an MCITP:DBA for 2005! This is TSQL, SSIS, vbscript, and powershell code I've implemented. For professional SQL Server developers only.
Wednesday, September 1, 2010
SSIS - FTP using Script Task
I was asked to write a SSIS package to download a file from a website (using FTP with a WWW... weird) at 2:00 am automatically. SSIS's FTP tool couldn't do it because it passes the username and password on the URL. (Rotten idea from a security POV, but that's what I was given.) It took me about two weeks, but I cobbled this code together. I had to perform several more major steps after getting the code to run, and I hope I remember them all here. To get it to run automatically:
- Create your SSIS package (.dtsx)
- Copy just the .dtsx file to the directory where you want to run it from
- Create a new domain user with "Log on as a batch file" permissions
- If your SSIS package connects to a database, add that user as a login on your SQL Server (Server / Security / Logins).
- On the database server you want to run it on, create a batch file to execute your SSIS package. The "output.txt" file pipes the output to a separate file, which can be very handy.
d:cd \directorydtexec /FILE "your-file-name.dtsx" /CHECKPOINTING OFF /REPORTING E > "your-file-name-lastrun-output.txt" - Launch Task Scheduler on the machine you want to run it on, give it the name of your batch file, give it a schedule, and tell it to execute as that new domain user.
' Microsoft SQL Server Integration Services Script Task
' Write scripts using Microsoft Visual Basic
' The ScriptMain class is the entry point of the Script Task.
Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime
Imports System.Net
Imports System.IO
Imports System.Collections.Generic
Imports System.Text
<system.addin.addin("scriptmain", )="" ,="" description:="" publisher:="" version:="1.0"> _
<system.clscompliantattribute(false)> _
Partial Public Class ScriptMain
Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
Enum ScriptResults
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
End Enum
Public Sub Main()
Try
Dim restURL As New StringBuilder()
Dim objRequest As FtpWebRequest
Dim objResponse As FtpWebResponse
Dim objStream As StreamReader
Dim arySourceFiles(0) As String
Dim aryDestinationFiles(0) As String
Dim intFile As Int16
' - original file names from FTP site
arySourceFiles(0) = "original_filename.txt"
' - new file names - rename arySourceFiles(n) to aryDestinationFiles(n)
aryDestinationFiles(0) = "\\servername\d$\directory\new_filename.txt"
' - download each file
For intFile = 0 To UBound(arySourceFiles)
objRequest = DirectCast(FtpWebRequest.Create("ftp://nt_domainname%5Cusername:password@www.website.com/directory1/directory2/" & arySourceFiles(intFile)), FtpWebRequest)
objResponse = DirectCast(objRequest.GetResponse(), FtpWebResponse)
objStream = New StreamReader(objResponse.GetResponseStream())
File.WriteAllText(aryDestinationFiles(intFile), objStream.ReadToEnd)
Next
Dts.TaskResult = ScriptResults.Success
Catch webEx As WebException
Dim [error] As New StringBuilder()
'catch protocol errors
If webEx.Status = WebExceptionStatus.ProtocolError Then
[error].AppendFormat("Status code: ", DirectCast(webEx.Response, HttpWebResponse).StatusCode)
[error].AppendFormat("Status description: ", DirectCast(webEx.Response, HttpWebResponse).StatusDescription)
' post the error message we got back. This is the old error catch code that might work better with SSIS.
Dts.Events.FireError(0, String.Empty, webEx.Message.ToString(), String.Empty, 0)
Dts.TaskResult = ScriptResults.Failure
End If
End Try
End Sub
End Class
Subscribe to:
Posts (Atom)