SQL Script to clone database leaving original untouched - sql

we currently have a base installation of our CMS, in this CMS it contains a complete working dataset for users, products, content etc. We are looking to increase our installation time because right now we currently have to go into SQL Server 2012, create a new DB and then restore the DB from an existing base installation db.
This can take up to 10 - 15 minutes each installation we do.
We also make sure our base database has all the requirements for sites we build.
Our issue is, we would like to do the following.
have a script create a fresh new empty database
make a clone of this database into a new .bak file
Take this .bak file then reproduce this into a fresh new database with its own MDF and LDF files respectively.
the databases are on the same server so we dont need to migrate this across to any other machine or instance.
Our code is below
CREATE database my_test
BACKUP DATABASE test_db TO DISK = 'C:\my_test\my_test.bak' WITH INIT;
EXEC internal_lab_test.dbo.sp_helpfile;
RESTORE FILELISTONLY
FROM DISK = 'C:\my_test\my_test.bak'
RESTORE DATABASE my_test
FROM DISK = 'C:\my_test\my_test.bak'
WITH MOVE 'my_test' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db.mdf',
MOVE 'my_test_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db_log.ldf'
we want to make sure that everything is fresh and clean, but also still contain all the data, however everytime we run this code, we get the following error messages
we also want to make sure the original database mdf and ldf files are left in tact and arent used in the new database
Msg 3154, Level 16, State 4, Line 10
The backup set holds a backup of a database other than the existing 'my_test' database.
Msg 3013, Level 16, State 1, Line 10
RESTORE DATABASE is terminating abnormally.

I know this is old, but it was the 2nd entry in google so for completeness.
It is because the database already exists. so either drop the database or add with Replace.
Also the my_test and my_test_log names need to be the logical names from the restore filelistonly command.
RESTORE DATABASE my_test
FROM DISK = 'C:\my_test\my_test.bak'
WITH Replace,
MOVE 'my_test' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db.mdf',
MOVE 'my_test_log' TO 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\test_db_log.ldf'

Compleate script wroted by me that is enough flexible for common development task (clone db from 'template', apply incremental scripts, then drop cloned db).
Note: you should make your DB 'read_only, single_user' before procedure adv.cloneDatabase will be executed, and return original states after, also you need rights to execute xp_cmdshell.
CREATE PROCEDURE adv.alterateFileNames(
#mdfFileName nvarchar(256),
#ldfFileName nvarchar(256),
#newMdfFileName nvarchar(256) OUTPUT,
#newLdfFileName nvarchar(256) OUTPUT
)
AS
BEGIN
DECLARE #path_data nvarchar(256)
DECLARE #ext_data nvarchar(4)
DECLARE #path_log nvarchar(256)
DECLARE #ext_log nvarchar(4)
-- respect file extensions
if (RIGHT(#mdfFileName , 4)='.mdf')
BEGIN
SET #path_data = SUBSTRING(#mdfFileName,0,LEN(#mdfFileName)-3)
SET #ext_data = '.mdf'
END
ELSE
BEGIN
SET #path_data = #mdfFileName
SET #ext_data = ''
END
if (RIGHT(#ldfFileName , 4)='.ldf')
BEGIN
SET #path_log = SUBSTRING(#ldfFileName,0,LEN(#ldfFileName)-3)
SET #ext_log = '.ldf'
END
ELSE
BEGIN
SET #path_log = #ldfFileName
SET #ext_log = ''
END
-- respect suffix counters like dbname_2 (that means add value to them)
DECLARE #iData int
DECLARE #data_suffix_index int = len(#path_data) - charindex('_', reverse(#path_data))
IF (#data_suffix_index < len(#path_data)-1 AND #data_suffix_index > 0 )
BEGIN
DECLARE #data_suffix nvarchar(128) = substring(#path_data, #data_suffix_index+2, len(#path_data)-#data_suffix_index-1 )
IF #data_suffix NOT LIKE '%[^0-9]%'
BEGIN
SET #path_data = SUBSTRING(#path_data,0,#data_suffix_index+1)
SET #iData = CAST(#data_suffix as int);
END
END
IF (#iData is null)
BEGIN
SET #path_data = #path_data
SET #iData = 0
END
DECLARE #iLog int
DECLARE #log_suffix_index int = len(#path_log) - charindex('_', reverse(#path_log))
IF (#log_suffix_index < len(#path_log)-1 AND #log_suffix_index > 0 )
BEGIN
DECLARE #log_suffix nvarchar(128) = substring(#path_log, #log_suffix_index+2, len(#path_log) - #log_suffix_index-1 )
IF #log_suffix NOT LIKE '%[^0-9]%'
BEGIN
SET #path_log = SUBSTRING(#path_log,0,#log_suffix_index+1)
SET #iLog = CAST(#log_suffix as int);
END
END
IF (#iLog is null)
BEGIN
SET #path_log = #path_log
SET #iLog = 0
END
WHILE 1=1
BEGIN
IF EXISTS(SELECT * FROM sys.master_files WHERE physical_name=#path_data+'_'+CAST(#iData AS varchar(6))+#ext_data)
SET #iData=#iData+1
ELSE
BEGIN
SET #path_data= #path_data+'_'+CAST(#iData AS varchar(6))+#ext_data
BREAK
END
END
WHILE 1=1
BEGIN
IF EXISTS(SELECT * FROM sys.master_files WHERE physical_name=#path_log+'_'+CAST(#iLog AS varchar(6))+#ext_log)
SET #iLog=#iLog+1
ELSE
BEGIN
SET #path_log= #path_log+'_'+CAST(#iLog AS varchar(6))+#ext_log
BREAK
END
END
SET #newMdfFileName = #path_data
SET #newLdfFileName = #path_log
END
GO
CREATE PROCEDURE adv.cloneDatabase
(
#databaseName sysname,
#newDatabaseName sysname
)
AS
BEGIN
SET NOCOUNT ON
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName)
THROW 50000, 'Database doesn''t exist', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND owner_sid<>0x01)
THROW 50000, 'Clonning of system database is not supported', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND is_read_only=1)
THROW 50000, 'Clonning of not readonly database is not supported', 1;
IF NOT EXISTS ( SELECT * FROM sys.databases WHERE name = #databaseName AND user_access=1 /*single user*/)
THROW 50000, 'Clonning of nor single_user database is not supported', 1;
-- collect file info
DECLARE #Files TABLE
(
[type] int, /*0,1,2,3,4*/
type_desc nvarchar(60), /*ROWS,LOG,FILESTREAM,FULLTEXT*/
name sysname,
physical_name nvarchar(260)
)
INSERT INTO #Files ([type], type_desc, name, physical_name)
SELECT [type], type_desc, f.name, physical_name
FROM sys.master_files f INNER JOIN sys.databases d ON f.database_id=d.database_id
WHERE d.name=#databaseName
-- test files
DECLARE #filesCount int
SELECT #filesCount = count(*) from #Files
IF (#filesCount<>2)
THROW 50000, 'The procedure doesn''t support complex file structures', 1;
DECLARE #mdfFileName nvarchar(260), #ldfFileName nvarchar(260)
SELECT #mdfFileName = physical_name FROM #Files WHERE type_desc='ROWS'
SELECT #ldfFileName = physical_name FROM #Files WHERE type_desc='LOG'
DECLARE #newMdfFileName nvarchar(260), #newLdfFileName nvarchar(260)
exec adv.alterateFileNames #mdfFileName, #ldfFileName, #newMdfFileName=#newMdfFileName OUTPUT, #newLdfFileName=#newLdfFileName OUTPUT
DECLARE #cmd1 nvarchar(4000)= 'copy /Y "#mdfFileName" "#newMdfFileName"'
DECLARE #cmd2 nvarchar(4000)= 'copy "#ldfFileName" "#newLdfFileName"'
SET #cmd1=replace(#cmd1,'#mdfFileName',#mdfFileName)
SET #cmd1=replace(#cmd1,'#newMdfFileName',#newMdfFileName)
SET #cmd2=replace(#cmd2,'#ldfFileName',#ldfFileName)
SET #cmd2=replace(#cmd2,'#newLdfFileName',#newLdfFileName)
DECLARE #OUTPUT TABLE (line text)
DECLARE #result INT
BEGIN TRY
INSERT INTO #OUTPUT (line) VALUES ('> '+#cmd1)
INSERT INTO #OUTPUT
exec #result =xp_cmdshell #cmd1
INSERT INTO #OUTPUT (line) VALUES ('> '+#cmd2)
IF (#result <> 0)
THROW 50000, 'Error copying mdf file',1
INSERT INTO #OUTPUT
exec #result =xp_cmdshell #cmd2
IF (#result <> 0)
THROW 50000, 'Error copying ldf file',1
END TRY
BEGIN CATCH
SELECT * FROM #OUTPUT WHERE line is not null;
THROW
END CATCH
DECLARE #createDatabaseSql nvarchar(max)
SET #createDatabaseSql = '
CREATE DATABASE '+#newDatabaseName+'
ON (FILENAME = '''+#newMdfFileName+'''),
(FILENAME = '''+#newLdfFileName+''')
FOR ATTACH;'
exec sp_executesql #stmt = #createDatabaseSql
END
GO

Related

SQL Server restore proc with database name parameter

Looking for a stored procedure to restore from a .bak file, but would like to be able to enter the db name as a parameter, i.e. Exec sp_restore #dbname
The paths to the .bak will be identical for all the dbs i.e. all dbs are dev copies of the same production backup.
Each .mdf and .ldf will have the same name as the db itself i.e.
dbname = #dbname, mdf = D:\data\#dbname.mdf, ldf =D:\data\#dbname.ldf
The paths to .mdf and .ldf will be the identical for each db, i.e. D:\data\#dbname.mdf
Using Sql Server Management Studio, you can start performing a restore operation. Before completing the task, you should be able to see a "Script" button. This will create a script with all the parameters you have manually entered, including mdf and ldf location. You can then save this script and execute it at will. You can also modify the resulting script to make the database name an input variable. You can do anything really. It's SQL!
A sample script that restores a database and changes mdf and ldf file locations would look like this:
RESTORE DATABASE [example] FROM DISK = N'E:\Backup\example.BAK' WITH FILE = 1, MOVE N'ExampleData' TO N'E:\dbfiles\example.mdf', MOVE N'example_log' TO N'E:\dbfiles\example.ldf', NOUNLOAD, STATS = 10
GO
You can read more about the RESTORE statement
You can then insert the script in a stored procedure as such:
CREATE PROCEDURE RestoreDb
-- Add the parameters for the stored procedure here
#dbName nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
RESTORE DATABASE #dbName FROM DISK = N'C:\Data\MSSQL\Backup\lolwut.bak' WITH FILE = 1, NOUNLOAD, STATS = 10
END
GO
Procedure for restore DB from bak-file #DeviceName. It works with DBs, wich have two logical files.
How to use:
EXEC RestoreDb #dbName='qqq', #DeviceName = 'D:\temp\1\R.bak'
Sorry for my English, I improve it.
CREATE PROCEDURE RestoreDb
#dbName NVARCHAR(50),
#DeviceName NVARCHAR(400)
AS
SET NOCOUNT ON
DECLARE #Cmd NVARCHAR(1000),
#DataLogicalName NVARCHAR(200),
#LogLogicalName NVARCHAR(200),
#DatabasePath NVARCHAR(200),
#DataPath NVARCHAR(300),
#LogPath NVARCHAR(300)
CREATE TABLE #Files
(
LogicalName nvarchar(128),
PhysicalName nvarchar(260),
[Type] char(1),
FileGroupName nvarchar(128),
Size numeric(20,0),
MaxSize numeric(20,0),
FileID bigint,
CreateLSN numeric(25,0),
DropLSN numeric(25,0),
UniqueID uniqueidentifier,
ReadOnlyLSN numeric(25,0) ,
ReadWriteLSN numeric(25,0),
BackupSizeInBytes bigint,
SourceBlockSize int,
FileGroupID int,
LogGroupGUID uniqueidentifier,
DifferentialBaseLSN numeric(25,0),
DifferentialBaseGUID uniqueidentifier,
IsReadOnly bit,
IsPresent bit,
TDEThumbprint varbinary(32)
)
SELECT #DatabasePath = 'D:\data\'
SELECT #DataPath = #DatabasePath + #dbName + '.mdf',
#LogPath = #DatabasePath + #dbName + '.ldf'
SELECT #Cmd = 'RESTORE FILELISTONLY
FROM DISK = ''' + #DeviceName + ''''
INSERT #Files
EXEC (#Cmd)
IF NOT EXISTS(SELECT 1 FROM #Files) GOTO ERRORFILES
IF (SELECT COUNT(*) FROM #Files) > 2 GOTO ERRORFILESCOUNT
SELECT #DataLogicalName = LogicalName
FROM #Files
WHERE [Type] = 'D'
SELECT #LogLogicalName = LogicalName
FROM #Files
WHERE [Type] = 'L'
RESTORE DATABASE #DbName
FROM DISK = #DeviceName
WITH
MOVE #DataLogicalName TO #DataPath,
MOVE #LogLogicalName TO #LogPath
GOTO EXITSTAT
ERRORFILES:
BEGIN
RAISERROR( 'The list of files contained in the backup set is empty', 16, 1 )
GOTO EXITSTAT
END
ERRORFILESCOUNT:
BEGIN
RAISERROR( 'The count of files contained in the backup set is more than two', 16, 1 )
GOTO EXITSTAT
END
EXITSTAT:

Scripted Restore Using xp_DirTree For Transient Logical BAK File Name SQL Server

Hi I am trying to restore a DB from one server to another where the logical name of the .bak file changes daily with a new timestamp, I have so far found success in determining this name using the following SQL script provided by Jeff Moden here: http://www.sqlservercentral.com/Forums/Topic1200360-391-1.aspx
--===== Create a holding table for the file names
CREATE TABLE #File
(
FileName SYSNAME,
Depth TINYINT,
IsFile TINYINT
)
;
--===== Capture the names in the desired directory
-- (Change "C:\Temp" to the directory of your choice)
INSERT INTO #File
(FileName, Depth, IsFile)
EXEC xp_DirTree '\\filepath\',1,1
;
--===== Find the latest file using the "constant" characters
-- in the file name and the ISO style date.
SELECT TOP 1
FileName
FROM #File
WHERE IsFile = 1
AND FileName LIKE '%.bak' ESCAPE '_'
ORDER BY FileName DESC
;
DROP TABLE #File
My question is now how do I use this as the basis of a scripted restore operation? any help would be very much appreciated!
I have found success by extending the above to cache the directory path and ordered bak files chronologically to determine which to use, then combined the restore operation, with move for logs.
--==CHECK IF DB EXISTS IF IT DOES DROP IT
USE [master]
IF EXISTS(SELECT * FROM sys.databases where name='insert db name')
DROP DATABASE [insert db name]
--==START THE RESTORE PROCESS
DECLARE #FileName varchar(255), #PathToBackup varchar(255), #RestoreFilePath varchar(1000)
DECLARE #Files TABLE (subdirectory varchar(255), depth int, [file] int)
SET NOCOUNT ON
--==SET THE FILEPATH
SET #PathToBackup = '\\insert path to back up'
--insert into memory table using dirtree at a single file level
INSERT INTO #Files
EXEC master.dbo.xp_DirTree #PathToBackup,1,1
SELECT TOP 1
#FileName = [subdirectory]
FROM
#Files
WHERE
-- get where it is a file
[file] = 1
AND
--==FIND THE LOGICAL NAME OF THE BAK FILE FROM THE CHRONILOGICALLY ORDERED LIST
subdirectory LIKE '%.bak'
ORDER BY
-- order descending so newest file will be first by naming convention
subdirectory DESC
IF LEFT(REVERSE(#PathToBackup), 1) != '\'
BEGIN
SET #PathToBackup = #PathToBackup + '\'
END
SET #RestoreFilePath = #PathToBackup + #FileName
--Grab the file path to restore from
SELECT #RestoreFilePath
--BEGIN THE RESTORE TO THE DESIGNATED SERVER
RESTORE DATABASE [insert name of database to restore]
FROM DISK = #RestoreFilePath
WITH
FILE = 1,
--Create transactional log files on target
MOVE 'mdf_file_name' TO 'file_path\file.mdf',
MOVE 'log_file_name' TO 'file_path\file.ldf', REPLACE;
Here is a script that I have partly written and partly collected.
Features include:
Imports exactly one backup file that has any file name with .bak
ending. If there are more files, then imports only one without any
errors.
If no files exist, gives an error.
Kicks users out from the database.
Deletes the backup file
DECLARE #DBName nvarchar(255), #FileName nvarchar(255), #PathToBackup nvarchar(255), #RestoreFilePath nvarchar(1000)
DECLARE #Files TABLE (subdirectory nvarchar(255), depth int, [file] int)
SET XACT_ABORT, NOCOUNT ON
SET #PathToBackup = N'I:\Folder'
-- insert into our memory table using dirtree and a single file level
INSERT INTO #Files
EXEC master.dbo.xp_DirTree #PathToBackup,1,1
SELECT
#FileName = [subdirectory]
FROM
#Files
WHERE
-- get where it is a file
[file] = 1
AND
subdirectory LIKE N'%.bak'
ORDER BY
-- order descending so newest file will be first by naming convention
subdirectory DESC
IF LEFT(REVERSE(#PathToBackup), 1) != N'\'
BEGIN
SET #PathToBackup = #PathToBackup + N'\'
END
SET #RestoreFilePath = #PathToBackup + #FileName
SET #DBName = LEFT(#FileName, LEN(#FileName)-4)
-- SELECT 'Replace AdventureWorks2016CTP3 in this script with #DBName'
SELECT #RestoreFilePath
BEGIN TRY
-- You can try to check if this command works "already":
-- ALTER DATABASE [#DBName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [AdventureWorks2016CTP3] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
-- You can try to check if this command works "already":
-- RESTORE DATABASE [#DBName]
RESTORE DATABASE [AdventureWorks2016CTP3]
FROM DISK = #RestoreFilePath
WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10
END TRY
BEGIN CATCH
-- You can try to check if this command works "already":
-- ALTER DATABASE [#DBName] SET MULTI_USER;
ALTER DATABASE [AdventureWorks2016CTP3] SET MULTI_USER;
; THROW
END CATCH
-- You can try to check if this command works "already":
-- ALTER DATABASE [#DBName] SET MULTI_USER;
ALTER DATABASE [AdventureWorks2016CTP3] SET MULTI_USER;
-- This script is especially for the case where you replication from one location to another using backup and restore.
-- Typically you don't need transaction log backups as all changes will be wiped out on next transfer.
-- You can try to check if this command works "already":
-- ALTER DATABASE [#DBName] SET RECOVERY SIMPLE;
ALTER DATABASE [AdventureWorks2016CTP3] SET RECOVERY SIMPLE;
-- Delete file(s)
-- NOTE: This works only if you give deletion permissions as defined in https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/xp-cmdshell-server-configuration-option?view=sql-server-2017
-- EXAMPLE: exec xp_cmdshell 'del "I:\Directory\AdventureWorks2016CTP3___.bak"'
-- exec xp_cmdshell 'del "' + '#PathToBackup + ''\'' + #FileName + ''"''
DECLARE #cmd NVARCHAR(MAX) = 'xp_cmdshell ''del "' + #PathToBackup + #FileName + '"''';
-- SELECT #cmd
EXEC (#cmd)

How can I verify that a file exists in Windows with SQL?

I have a SQL Server running on my Windows Server and, at a specific column of a table, I have the path for a Zip file (which in turn has the source of the data stored in the database). Some of these are not valid (do not match the data in database). I need to make SQL Server verify that these Zip files exist and that they match the column that stores the path and name of the zip file. This way I will delete the wrong file-path column correspondences.
you can use the undocumented proc xp_fileexist will return 1 if it exists and 0 otherwise
SET NOCOUNT ON
DECLARE #iFileExists INT
EXEC master..xp_fileexist 'c:\bla.txt',
#iFileExists OUTPUT
select #iFileExists
You can use xp_fileexist however please note it is undocumented and unsupported.
You can use SQLCLR, however you didn't bother specifying what version of SQL Server you're using, so it may not be relevant - and in any case it is disabled by default, and security policies prevent its use in some places.
You can use a #temp table and xp_cmdshell, however xp_cmdshell is typically disabled for the same reasons as SQLCLR.
/* if you need to enable xp_cmdshell:
exec master..sp_configure 'show adv', 1;
reconfigure with override;
exec master..sp_configure 'xp_cmdshell', 1;
reconfigure with override;
exec master..sp_configure 'show adv', 0;
reconfigure with override;
*/
SET NOCOUNT ON;
DECLARE
#file VARCHAR(1000),
#path VARCHAR(255),
#cmd VARCHAR(2048);
SELECT
#file = 'foo.zip',
#path = 'C:\wherever\';
SELECT #cmd = 'dir /b "' + #path + #file + '"';
CREATE TABLE #x(a VARCHAR(1255));
INSERT #x EXEC master..xp_cmdshell #cmd;
IF EXISTS (SELECT 1 FROM #x WHERE a = #file)
PRINT 'file exists';
ELSE
PRINT 'file does not exist';
DROP TABLE #x;
EDIT based on new requirements. It shows a list of files either in the table or in the database, and indicates whether the file is in only one location or both. It assumes that path + file is <= 900 characters long (merely to be able to use an index on at least one side).
USE tempdb;
GO
CREATE TABLE dbo.files(f VARCHAR(1000));
INSERT dbo.files(f) SELECT 'zip_that_does_not_exist.zip'
UNION ALL SELECT 'c:\path\file_that_does_not_exist.zip'
UNION ALL SELECT 'c:\path\file_that_exists.zip'
UNION ALL SELECT 'zip_that_exists.zip';
DECLARE
#path VARCHAR(255),
#cmd VARCHAR(2048);
SELECT
#path = path_column,
#cmd = 'dir /b "' + path_column + '"'
FROM
dbo.table_that_holds_path;
CREATE TABLE #x(f VARCHAR(900) UNIQUE);
INSERT #x EXEC master..xp_cmdshell #cmd;
DELETE #x WHERE f IS NULL;
UPDATE #x SET f = LOWER(f);
WITH f AS
(
SELECT f = REPLACE(LOWER(f), LOWER(#path), '')
FROM dbo.files
)
SELECT
[file] = COALESCE(x.f, f.f),
[status] = CASE
WHEN x.f IS NULL THEN 'in database, not in folder'
WHEN f.f IS NULL THEN 'in folder, not in database'
ELSE 'in both' END
FROM
f FULL OUTER JOIN #x AS x
ON x.f = f.f;
DROP TABLE #x, dbo.files;

how to pass all database (fast) since sql server 2008 express to sql server 2008 R2 (NO express)

well i had sql 2008 express, and now i have installed, sql server, now i want to delete sql express, but in that instance i have all my database i have worked (plus of 20), so they are very important for me, how can i pass it to sql server 2008 r2, i know i can do database of all but i dont want to work a lot of, there is a way short, for to pass al database? coping a folder? something? thanks!
I Attached all database, and i added, all (but one for one) i added all in the same windows and in 5 minutos i had all database in sql (no express)
Create an SSIS package with 4 steps.
First, a Execute SQL task that backups all DBs to a specific location:
exec sp_msforeachdb '
IF DB_ID(''?'') > 4
Begin
BACKUP DATABASE [?] TO DISK = N''\\Backups\?.BAK'' WITH NOFORMAT, INIT,
NAME = N''?-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD
declare #backupSetId as int
select #backupSetId = position from msdb..backupset where database_name=N''?''
and backup_set_id=(select max(backup_set_id) from msdb..backupset
where database_name=N''?'' )
if #backupSetId is null begin
raiserror(N''Verify failed. Backup information for database ''''?'''' not found.'', 16, 1)
end
RESTORE VERIFYONLY FROM DISK = N''\\Backups\?.BAK'' WITH
FILE = #backupSetId, NOUNLOAD, NOREWIND
End
'
Second, Create a SP to restore DBs using a variable for location and DB name:
CreatePROCEDURE [dbo].[uSPMas_RestoreDB] #DBname NVARCHAR(200),
#BackupLocation NVARCHAR(2000)
AS
BEGIN
SET nocount ON;
create table #fileListTable
(
LogicalName nvarchar(128),
PhysicalName nvarchar(260),
[Type] char(1),
FileGroupName nvarchar(128),
Size numeric(20,0),
MaxSize numeric(20,0),
)
insert into #fileListTable EXEC('RESTORE FILELISTONLY FROM DISK = '''+#BackupLocation+#dbname+'.bak''')
Declare #Dname varchar(500)
Set #Dname = (select logicalname from #fileListTable where type = 'D')
Declare #LName varchar(500)
Set #LName = (select logicalname from #fileListTable where type = 'L')
declare #sql nvarchar(4000)
SET #SQL = 'RESTORE DATABASE ['+ #dbname +'] FROM
DISK = N'''+#BackupLocation + #dbname +'.BAK'' WITH FILE = 1,
MOVE N'''+ #Dname +''' TO N''E:\YourLocation\'+ #dbname +'.mdf'',
MOVE N'''+ #LName +''' TO N''D:\Your2ndLocation\'+ #dbname +'_log.ldf'',
NOUNLOAD, REPLACE, STATS = 10'
exec sp_executesql #SQL
drop table #fileListTable
END
Third, Create a ForEach Loop Container and put a Execute Sql Statement with variable:
EXEC uSPMas_RestoreDB ? , ?
Use the for ForEach Loop Container to pass the variables
Fourth, Create a 'Transfer Logins' task to move over all DB logins

Delete backup files older than 7 days

Using osql command, SSQL backup of a database is created.
It is saved to Disk.
Then renamed to match the date of the day backup was taken.
All these files are saved in a single folder all the time.
for example:
Batch1.bat does the following
1) Created backup.bak
2) renamed to backup 12-13-2009.bak (this is done by the combination of % ~ - etc to get the date parameter)
This is now automated to take backup everyday by Task scheduler in Windows.
Can the batch file also be modified to delete backup files older than 7 days? if so, how ?
If it is not possible via batch file, other than manually deleting the files are there any other alternatives to automate the deleting job ?
Thanks in advance, Balaji S
If you have RoboCopy (part of the Windows Server 2003 Resource Kit Tools) installed.
The following lines can be added to your Batch1.bat file to move and delete files older than seven days:
ROBOCOPY C:\Temp\New C:\Temp\Old *.* /move /minage:7
DEL C:\Temp\Old\*.*
The first row moves all files that are older than seven days in the 'New' folder to the 'Old' folder.
The second row deletes all files in the 'Old' folder
I'm using the same technique to make a backup from database. I've created a stored procedure as follows.
Create Procedure [dbo].[CreateBackup]
As
Begin
Declare #path nvarchar(256),
#filename nvarchar(256),
#currentDateTime datetime
Set #currentDateTime = GetDate()
Set #path = 'C:\DBBackup\'
Set #filename = #path + Cast(DatePart(month, #currentDateTime) As nvarchar) + Cast(DatePart(day, #currentDateTime) As nvarchar) + '.bak'
Backup Database Foo To Disk = #filename
Set #currentDateTime = DateAdd(day, -3, #currentDateTime)
Set #filename = 'del ' + #path + Cast(DatePart(month, #currentDateTime) As nvarchar) + Cast(DatePart(day, #currentDateTime) As nvarchar) + '.bak'
Exec xp_cmdshell #filename
End
To use the xp_cmdshell, you should enable it before.
http://weblogs.sqlteam.com/tarad/archive/2006/09/14/12103.aspx
enter code hereThis procedure backup given database(s) for specified #retentionPeriod to a given network location (or local)
USE [master]
GO
/****** Object: StoredProcedure [dbo].[scrDoRemoteBackup] Script Date: 12/13/2009 09:20:20 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[scrDoRemoteBackup] as
set NoCount on
declare #dbName Varchar(100)
,#fName varchar(100)
,#RetentionPeriod Int -- in days
,#i int
,#n int
,#NetPath varchar(400)
,#BackupSetName Varchar(300)
,#params nvarchar(300)
,#q nvarchar(3400)
,#cmd nvarchar(4000)
,#error int
Declare #DataBases2Backup table(id int identity(1,1),dbName Varchar(100))
-- total back time 4:24 2nd Nov 06
set #NetPath='\\rapidsnet01s\RapidsDbBackup'
set #netPath='\\mail1\RapidsDbBackup'
set #netPath = '\\rapidsweb02p\Backup'
set #netPath='\\BUP2D-2K\_RapidsDB$\SAABZXO1D' -- 26th Feb 2008 - ap/li rapidsweb02p\backup space runout
set #netPath='\\saacsfs\RapidsBackup\SAABZXo1d' -- 22nd Oct 2009
---- insert all databaes to be backed up
--Insert #DataBases2Backup select 'Rapids'
--Insert #DataBases2Backup select 'GDC'
--Insert #DataBases2Backup select 'Master'
--
--
----Insert #DataBases2Backup select 'GDCComDev'
--
--Insert #DataBases2Backup select 'saaNCP'
----Insert #DataBases2Backup select 'US_Reps'
--Insert #DataBases2Backup select 'saaPackageWorx'
--Insert #DataBases2Backup select 'saaExtract'
Insert #DataBases2Backup select 'Master'
Insert #DataBases2Backup select 'QuickPickDBprod'
Insert #DataBases2Backup select 'QuickPickDBStaging'
--Set #RetentionPeriod = 13
Set #RetentionPeriod = 6 -- For Terry McCraith Jan06'09
select #n= count(*) from #DataBases2Backup
set #i = 1;
-- Set the Network path for the Backup location ;
-- ( re-establish the connection if the connection was broken)
set #q = 'net use '+#Netpath --+' * /USER:apeiris#armlink.com'
print #q
exec master.dbo.xp_cmdShell #q
While #i <= #n
Begin
select #dbName=dbName from #DataBases2Backup where id = #i
-- Get the backupset name prior to Retention Period
set #BackupSetName=#dbName+ dbo.fnGetDateNameBefore(GetDate(),#RetentionPeriod)
-- Delete the old backup device
set #q='Del '+#NetPath+'\'+#BackupSetName+'.bkp'
exec master.dbo.xp_cmdShell #q
-- Now get the current backupset name and backit up
set #BackupSetName=#dbName+ dbo.fnGetDateNameBefore(GetDate(),0)
set #fname = #netPath +'\'+#BackupSetName+'.bkp'
print 'Fname ='+#fname
Print 'Drop and Add Dumpdevice ' + #dbname + ' Fname='+#fname
exec #error=sp_dropDevice #dbname
print 'Error drop device-----------'+Convert(varchar,#error)+':'+Convert(varchar,##error)
exec #error=sp_addumpDevice 'disk',#dbName,#fname
exec sp_helpdevice #dbName
print 'Error -----------'+Convert(varchar,#error)
set #i=#i+1
if #error <> 0
Begin
print 'send alert'
exec saabzt01p.alerts.dbo.prDispatchAlertV2 'RemoteDBBackupError' ,##servername,'test','RemoteDBBackupError','test'
End
else
Begin
Backup Log #dbname with truncate_only
Backup Database #dbname to #dbname with format
if ##Error <> 0
Begin
print 'Send alert'
exec saabzt01p.alerts.dbo.prDispatchAlertV2 'RemoteDBBackupError',##servername,'test','RemoteDBBackupError','test'
Goto Errors
end
end
End
Errors:
And here are supporting functions
-- This function returns oldest data set name compared to retentionPeriod
Create function [dbo].[fnGetDateNameBefore](#d Datetime,#nDays int) returns varchar(40) as
Begin
declare #OD datetime
,#dName Varchar(40);
set #OD=DateAdd(dd,#nDays * -1,#d)
select #dName= DateName(yy,#od)+Left(DateName(Month,#od),3)+DateName(dd,#od)
Return #dName
end
-- This function returns oldest data set name compared to retentionPeriod
Create function [dbo].[fnGetDateNameBefore](#d Datetime,#nDays int) returns varchar(40) as
Begin
declare #OD datetime
,#dName Varchar(40);
set #OD=DateAdd(dd,#nDays * -1,#d)
select #dName= DateName(yy,#od)+Left(DateName(Month,#od),3)+DateName(dd,#od)
Return #dName
end
Nope don't do it that way. Do it this way.
Use SQL backup manager from the command line and script out a schedlue using Backup manager express. This is included and located in your SQL bin folder. Run this once, then modify the registry if it gives you an error. Then run again, ot should work. Perform this methodolgy to obtian your backups on a scheduled basis.