Attach multiple databases using T-SQL - sql

We are migrating one of our servers from SQL Server 2005 to SQL Server 2008.
This server has about 50 small databases on it.
The migration path we are taking goes as follows:
Create new server with SQL 2008
Shutdown SQL Services on old server and copy databases to new one
Shutdown old server and rename new server to the same name as the old one.
Attach the 50 databases
Is there a fast way using t-sql to attach the 50 databases to the new server?
All the data files are going to be located at E:\DATA and transaction logs are going to be located at E:\TLOG

Using the SQLCMD mode, you can easily script this:
:setvar dbname YourDatabaseName
:setvar dbfile N'E:\DATA\YourDatabase.mdf'
:setvar logfile N'E:\TLOG\YourDatabase_log.ldf'
USE [master]
GO
CREATE DATABASE $(dbname) ON
( FILENAME = $(dbfile) ),
( FILENAME = $(logfile) )
FOR ATTACH
GO
This works either from sqlcmd.exe from the command line (you can even supply the values for the variables dbname, dbfile, logfile from the command line, too), or it works in SQL Server Management Studio if you enabled Tools > Options > Query Execution > by default, open new queries in SQLCMD mode .
Read more about the SQLCMD utility and all its parameters on MSDN.
PS: of course, this approach with a SQLCMD enabled script also works for BACKUP/RESTORE cycles :-) (as recommended by Aaron)
PPS: if you have a good naming convention, and the data file is always $(dbname).mdf and the log file is always $(dbname)_log.ldf, you could also use this shortened SQLCMD script:
:setvar dbname YourDatabaseName
USE [master]
GO
CREATE DATABASE $(dbname) ON
( FILENAME = N'E:\DATA\$(dbfile).mdf' ),
( FILENAME = N'E:\TLOG\$(logfile)_log.ldf' )
FOR ATTACH
GO
and then just call this from the command line:
C:\> sqlcmd.exe -S yourserver -E -i attach.sql -v dbname=YourDb1
and so forth, once for each database you need to re-attach.
PPPS: if you want to restore backups, it's just slightly more complicated :
:setvar dbname YourDatabaseName
USE [master]
GO
RESTORE DATABASE $(dbname)
FROM DISK = N'E:\Backup\$(dbname).bak'
WITH FILE = 1,
MOVE N'$(dbname)' TO N'E:\DATA\$(dbname).mdf',
MOVE N'$(dbname)_Log' TO N'E:\TLOG\$(dbname)_Log.ldf',
NOUNLOAD, REPLACE
GO
This works, as long as you name your .bak files the same as your database name, and you put them in a fixed location (I presumed E:\Backup here - adapt as needed).

To re-iterate my comment, I suggest a backup/restore approach as opposed to a detach/attach approach (my reasons are outlined here and here).
And while I like #marc_s's SQLCMD approach, I prefer to pull this stuff from the metadata directly. This way I can inspect all of the output, copy and paste the parts I want to execute in batches instead of all at once, etc. Something like:
SET NOCOUNT ON;
DECLARE #folder nvarchar(512) = N'\\fileshare\folder\'; -- 'backup location
SELECT N'BACKUP DATABASE ' + QUOTENAME(name)
+ N' TO DISK = N''' + #folder + name + N'.BAK'' WITH INIT;
ALTER DATABASE ' + QUOTENAME(name) + N' SET OFFLINE;'
FROM sys.databases
WHERE database_id > 4 -- AND other filter criteria
SELECT N'RESTORE DATABASE ' + QUOTENAME(d.name)
+ N' FROM DISK = N''' + #folder + d.name + N'.BAK'' WITH '
+ STUFF(
(SELECT N',
MOVE N''' + f.name + N''' TO ''E:\DATA\' + f.name + '.mdf'''
FROM master.sys.master_files AS f
WHERE f.database_id = d.database_id
AND type_desc = N'ROWS'
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
+ N', ' + STUFF(
(SELECT N',
MOVE N''' + f.name + N''' TO N''E:\TLOG\' + f.name + N'.mdf'''
FROM master.sys.master_files AS f
WHERE f.database_id = d.database_id
AND type_desc = 'LOG'
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'') + N';
ALTER DATABASE ' + QUOTENAME(d.name)
+ N' SET COMPATIBILITY_LEVEL = 100;'
FROM sys.databases AS d
WHERE database_id > 4; -- AND other filter criteria
(This assumes that you only have data/log files, no filestream etc. and that you can backup to / restore from a common location accessible to both instances.)
To clarify, you would generate both sets of commands on the 2005 server, copy & run the backup commands there (and perhaps set them to offline immediately afterward), then copy & run the restore commands on the 2008 server.
You'll also want to update statistics on your key tables, otherwise you may be in for some serious head-scratching when your performance goes down the tubes as the plan cache on the new server gets primed...

Related

Backup script I've been using with no issues for a while tossing an error on new database

I've been using the code below to drop and create a new backup named (current year database)_daily at midnight to allow my team to test new scripts or updates to our student information system.
It worked all last year, and this year for reasons I can't figure out, the script is tossing an error.
Here is the script:
USE master;
GO
-- the original database (use 'SET #DB = NULL' to disable backup)
DECLARE #SourceDatabaseName varchar(200)
DECLARE #SourceDatabaseLogicalName varchar(200)
DECLARE #SourceDatabaseLogicalNameForLog varchar(200)
DECLARE #query varchar(2000)
DECLARE #DataFile varchar(2000)
DECLARE #LogFile varchar(2000)
DECLARE #BackupFile varchar(2000)
DECLARE #TargetDatabaseName varchar(200)
DECLARE #TargetDatbaseFolder varchar(2000)
-- ****************************************************************
SET #SourceDatabaseName = '[DST18000RD]' -- Name of the source database
SET #SourceDatabaseLogicalName = 'DST18000RD' -- Logical name of the DB ( check DB properties / Files tab )
SET #SourceDatabaseLogicalNameForLog = 'DST18000RD_log' -- Logical name of the DB ( check DB properties / Files tab )
SET #BackupFile = 'F:\Dev_Databases\Temp\backup.dat' -- FileName of the backup file
SET #TargetDatabaseName = 'DST18000RD_Daily' -- Name of the target database
SET #TargetDatbaseFolder = 'F:\Dev_Databases\Temp\'
-- ****************************************************************
SET #DataFile = #TargetDatbaseFolder + #TargetDatabaseName + '.mdf';
SET #LogFile = #TargetDatbaseFolder + #TargetDatabaseName + '.ldf';
-- Disconnect any users using #TargetDatabaseName
USE [master];
DECLARE #kill varchar(8000) = '';
SELECT #kill = #kill + 'kill ' + CONVERT(varchar(5), session_id) + ';'
FROM sys.dm_exec_sessions
WHERE database_id = db_id('DST18000RD_Daily')
EXEC(#kill);
-- Backup the #SourceDatabase to #BackupFile location
IF #SourceDatabaseName IS NOT NULL
BEGIN
SET #query = 'BACKUP DATABASE ' + #SourceDatabaseName + ' TO DISK = ' + QUOTENAME(#BackupFile,'''')
PRINT 'Executing query : ' + #query;
EXEC (#query)
END
PRINT 'OK!';
-- Drop #TargetDatabaseName if exists
IF EXISTS(SELECT * FROM sysdatabases WHERE name = #TargetDatabaseName)
BEGIN
SET #query = 'DROP DATABASE ' + #TargetDatabaseName
PRINT 'Executing query : ' + #query;
EXEC (#query)
END
PRINT 'OK!'
-- Restore database from #BackupFile into #DataFile and #LogFile
SET #query = 'RESTORE DATABASE ' + #TargetDatabaseName + ' FROM DISK = ' + QUOTENAME(#BackupFile,'''')
SET #query = #query + ' WITH MOVE ' + QUOTENAME(#SourceDatabaseLogicalName,'''') + ' TO ' + QUOTENAME(#DataFile ,'''')
SET #query = #query + ' , MOVE ' + QUOTENAME(#SourceDatabaseLogicalNameForLog,'''') + ' TO ' + QUOTENAME(#LogFile,'''')
PRINT 'Executing query : ' + #query
EXEC (#query)
PRINT 'OK!'
The script is not mine, I put together two scripts to get me what I needed. Our old database DST17000RD, this script still works flawlessly. On the new database DST18000RD, I get this error:
Executing query : BACKUP DATABASE [DST18000RD] TO DISK = 'F:\Dev_Databases\Temp\backup.dat'
Processed 1209552 pages for database 'DST18000RD', file 'DST18000RD' on file 23.
Processed 2 pages for database 'DST18000RD', file 'DST18000RD_log' on file 23.
BACKUP DATABASE successfully processed 1209554 pages in 139.942 seconds (67.525 MB/sec).
OK!
OK!
Executing query : RESTORE DATABASE DST18000RD_Daily FROM DISK = 'F:\Dev_Databases\Temp\backup.dat' WITH MOVE 'DST18000RD' TO 'F:\Dev_Databases\Temp\DST18000RD_Daily.mdf' , MOVE 'DST18000RD_log' TO 'F:\Dev_Databases\Temp\DST18000RD_Daily.ldf'
Msg 3234, Level 16, State 2, Line 3
Logical file 'DST18000RD' is not part of database 'DST18000RD_Daily'. Use RESTORE FILELISTONLY to list the logical file names.
Msg 3013, Level 16, State 1, Line 3
RESTORE DATABASE is terminating abnormally.
OK!
Some things to note that may just be me barking up the wrong tree. DST17000RD database is compatibility level SQL Server 2012 (110) and the DST18000RD database is SQL Server 2017 (140). The server was upgraded and migrated a couple months ago before the new database was created.
Any help is appreciated. From what I can tell, I feel like the script is not renaming the MDF and LDF files before it tries to copy them for the *_daily database? Honestly I'm not sure. I'm a pretend DBA, self taught on an as needed basis. Thank you in advance for your help!
The error is telling you got the logical name of the db file wrong:
SET #SourceDatabaseLogicalName = 'DST18000RD' -- Logical name of the DB ( check DB properties / Files tab )
and to run:
RESTORE FILELIST ONLY FROM DISK = 'F:\Dev_Databases\Temp\backup.dat'
To see the correct logical file names.
The issue is you are trying to change the file logical name during the database restore, which is not possible even if you use the MOVE clause.
The MOVE clause allows you to change the location and the names of the physical files but does not do anything for the logical names.
Fix
You will have to use the existing logical names for your database, but once you have restored the database then use ALTER DATABASE command to change the logical names of your files using the following command:
USE [master];
GO
ALTER DATABASE [DST18000RD]
MODIFY FILE ( NAME = DST17000RD , NEWNAME = DST18000RD );
GO

Copy local SQL database onto Azure

I want to do the - should be simple - task of copying a database from local to live...
I have all the data and table structure I want in my local database.
I have a currently running database live database that has all the backup stuff assigned to it etc so I don't just want to create a brand new database (not that I can find how to do this either)...
I just want to remove all tables from that database and then copy all my data and tables from the local into the live azure sql database.
How do I do this???
you can try to achieve this with SQL Server Management Studio.
If you goto SQL Management Studio, right click on the database you want to copy data for...
Goto Tasks Generate Script
Select just your tables not the entire database object
Open up your azure database in Visual Studio that you want to create the copy into
Open a new query for that database and paste the generated script in
Execute and pray to the gods
Jump around because it worked, now run the following command on the azure table to disable foreign key migrations:
DECLARE #sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT #sql += N'ALTER TABLE ' + obj + ' NOCHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql #sql;
now go into sql server management studio and right click on your local database and goto tasks and then export data
export to your azure database but make sure to edit the mappings and tick the identity box.
the data is moved, now set the foreign keys back using this on your azure database:
DECLARE #sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT #sql += N'ALTER TABLE ' + obj + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql #sql;

How to move tables from one sql server database to another?

We have a database that has grown to about 50GB and we want to pull out a certain set of tables (about 20 of them) from within that database and move them into a new database. All of this would be on the same SQL Server. The tables that we want to pull out are about 12GB of space (6GB data, 6GB indexes).
How can we move the tables from one database to the second but make sure the tables that are created in the new database are an exact copy of the originals (indexes, keys, etc.)? Ideally I want a copy/paste from within SQL Server Management Studio but I know this does not exist, so what are my options?
To do this really easily with SQL Server 2008 Management Studio:
1.) Right click on the database (not the table) and select Tasks -> Generate Scripts
2.) Click Next on the first page
3.) If you want to copy the whole database, just click next. If you want to copy specific tables, click on "Select Specific Database Objects", select the tables you want, and then click next.
4.) Select "Save to Clipboard" or "Save to File". IMPORTANT: Click the Advanced button next to "Save to File", find "Types of data to script", and change "Schema only" to "Schema and data" (if you want to create the table) or "Data only" (if you're copying data to an existing table). This is also where you'd set other options such as exactly what keys to copy, etc.
5.) Click through the rest and you're done!
If you're moving the tables to a whole new database just because of growth, you might be better off considering using filegroups in your existing database instead. There will be a lot fewer headaches going forward than trying to deal with two separate databases.
EDIT
As I mentioned in my comments below, if you truly need a new database, depending on the total number of tables involved, it might be easier to restore a backup of the database under the new name and drop the tables you don't want.
I did also find this potential solution using SQL Server Management Studio. You can generate the scripts for the specific tables to move and then export the data using the Generate Scripts Wizard and Import/Export Wizard in SQL Server Management Studio. Then on the new database you would run the scripts to create all of the objects and then import the data. We are probably going to go with the backup/restore method as described in #Joe Stefanelli's answer but I did find this method and wanted to post it for others to see.
To generate the sql script for the objects:
SQL Server Management Studio > Databases > Database1 > Tasks > Generate Scripts...
The SQL Server Scripts Wizard will start and you can choose the objects and settings to export into scripts
By default the scripting of Indexes and Triggers are not included so make sure to trun these on (and any others that you are interested in).
To export the data from the tables:
SQL Server Management Studio > Databases > Database1 > Tasks > Export Data...
Choose the source and destination databases
Select the tables to export
Make sure to check the Identity Insert checkbox for each table so that new identities are not created.
Then create the new database, run the scripts to create all of the objects, and then import the data.
If you like/have SSIS you can explore using the Copy SQL Objects Task component to do this.
Try DBSourceTools.
http://dbsourcetools.codeplex.com.
This toolset uses SMO to script tables and data to disk, and also allows you to select which tables / views / Stored procedures to include.
When using a "deployment target", it will also automatically handle dependencies.
I have used it repeatedly for exactly this type of problem, and it's extremely simple and fast.
SELECT *
INTO new_table_name [IN new database]
FROM old_tablename
A lazy, efficient way to do this in T-SQL:
In my case, some of the tables are large, so scripting out the data is impractical.
Also, we needed to migrate just a fraction of an otherwise very large database, so I didn't want to do backup / restore.
So I went with INSERT INTO / SELECT FROM and used information_schema etc to generate the code.
Step 1: create your tables on new DB
For every table you want to migrate to new database, create that table on new database.
Either script out the tables, or use SQL Compare, dynamic sql from information_schema -- many ways to do it. dallin's answer shows one way using SSMS (but be sure to select schema only).
Step 2: create UDF on target DB to produce column list
This is just a helper function used in generation of code.
USE [staging_edw]
GO
CREATE FUNCTION dbo.udf_get_column_list
(
#table_name varchar(8000)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #var VARCHAR(8000)
SELECT
#var = COALESCE(#var + ',', '', '') + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.columns c
WHERE c.TABLE_SCHEMA + '.' + c.TABLE_NAME = #table_name
AND c.COLUMN_NAME NOT LIKE '%hash%'
RETURN #var
END
Step 3: create log table
The generated code will log progress into this table so you can monitor. But you have to create this log table first.
USE staging_edw
GO
IF OBJECT_ID('dbo.tmp_sedw_migration_log') IS NULL
CREATE TABLE dbo.tmp_sedw_migration_log
(
step_number INT IDENTITY,
step VARCHAR(100),
start_time DATETIME
)
Step 4: generate migration script
Here you generate the T-SQL that will migrate the data for you. It just generates INSERT INTO / SELECT FROM statements for every table, and logs its progress along the way.
This script does not actually modify anything. It just outputs some code, which you can inspect before executing.
USE staging_edw
GO
-- newline characters for formatting of generated code
DECLARE #n VARCHAR(100) = CHAR(13)+CHAR(10)
DECLARE #t VARCHAR(100) = CHAR(9)
DECLARE #2n VARCHAR(100) = #n + #n
DECLARE #2nt VARCHAR(100) = #n + #n + #t
DECLARE #nt VARCHAR(100) = #n + #t
DECLARE #n2t VARCHAR(100) = #n + #t + #t
DECLARE #2n2t VARCHAR(100) = #n + #n + #t + #t
DECLARE #3n VARCHAR(100) = #n + #n + #n
-- identify tables with identity columns
IF OBJECT_ID('tempdb..#identities') IS NOT NULL
DROP TABLE #identities;
SELECT
table_schema = s.name,
table_name = o.name
INTO #identities
FROM sys.objects o
JOIN sys.columns c on o.object_id = c.object_id
JOIN sys.schemas s ON s.schema_id = o.schema_id
WHERE 1=1
AND c.is_identity = 1
-- generate the code
SELECT
#3n + '-- ' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#n + 'BEGIN TRY',
#2nt + IIF(i.table_schema IS NOT NULL, 'SET IDENTITY_INSERT staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' ON ', ''),
#2nt + 'TRUNCATE TABLE staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#2nt + 'INSERT INTO staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' WITH (TABLOCKX) ( ' + f.f + ' ) ',
#2nt + 'SELECT ' + f.f + + #nt + 'FROM staging.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME,
#2nt + IIF(i.table_schema IS NOT NULL, 'SET IDENTITY_INSERT staging_edw.' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' OFF ', ''),
#2nt + 'INSERT INTO dbo.tmp_sedw_migration_log ( step, start_time ) VALUES ( ''' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' inserted successfully'', GETDATE() );' ,
#2n + 'END TRY',
#2n + 'BEGIN CATCH',
#2nt + 'INSERT INTO dbo.tmp_sedw_migration_log ( step, start_time ) VALUES ( ''' + t.TABLE_SCHEMA + '.' + t.TABLE_NAME + ' FAILED'', GETDATE() );' ,
#2n + 'END CATCH'
FROM INFORMATION_SCHEMA.tables t
OUTER APPLY (SELECT f = staging_edw.dbo.udf_get_column_list(t.TABLE_SCHEMA + '.' + t.TABLE_NAME)) f
LEFT JOIN #identities i ON i.table_name = t.TABLE_NAME
AND i.table_schema = t.TABLE_SCHEMA
WHERE t.TABLE_TYPE = 'base table'
Step 5: run the code
Now you just copy the output from step 4, paste into new query window, and run.
Notes
In step 1, I exclude hash columns from the column list (in the UDF) because those are computed columns in my situation

How to build a script to backup all databases in SQL Server?

We need to backup 40 databases inside a SQL Server instance. We backup each database with the following script:
BACKUP DATABASE [dbname1] TO DISK = N'J:\SQLBACKUPS\dbname1.bak' WITH NOFORMAT, INIT, NAME = N'dbname1-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
declare #backupSetId as int
select #backupSetId = position from msdb..backupset where database_name=N'dbname1' and backup_set_id=(select max(backup_set_id) from msdb..backupset where database_name=N'dbname1' )
if #backupSetId is null begin raiserror(N'Verify failed. Backup information for database ''dbname1'' not found.', 16, 1) end
RESTORE VERIFYONLY FROM DISK = N'J:\SQLBACKUPS\dbname1.bak' WITH FILE = #backupSetId, NOUNLOAD, NOREWIND
GO
We will like to add to the script the functionality of taking each database and replacing it in the above script. Basically a script that will create and verify each database backup from an engine.
I am looking for something like this:
For each database in database-list
sp_backup(database) // this is the call to the script above.
End For
any ideas?
Use SqlBackupAndFTP. Select "Backup all non-system databases"
Maybe you can check the sp_MSForEachDB stored procedure.
EXEC sp_MSForEachDB 'EXEC sp_backup ?'
Where the ? mark stands for the current database on each iteration.
You said "verify" too... This would require a 2nd statement per database (RESTORE VERIFYONLY, as well the other answers offered.
I'd investigate using maintenance plans to include index maintenance too...
Something like:
DECLARE #SQL varchar(max)
SET #SQL = ''
SELECT #SQL = #SQL + 'BACKUP ' + Name + ' To Disk=''c:\' + Name + '.bak'';'
FROM sys.sysdatabases
EXEC(#SQL)
SQL Backup Master has the ability to back up all databases on a given server instance and then send the backups to Dropbox, FTP, Amazon S3, Google Drive, or local/network folder.

How can I schedule a daily backup with SQL Server Express? [duplicate]

This question already has answers here:
SQL Server Automated Backups [closed]
(3 answers)
Closed 5 years ago.
I'm running a small web application with SQL server express (2005) as backend. I can create a backup with a SQL script, however, I'd like to schedule this on a daily basis. As extra option (should-have) I'd like to keep only the last X backups (for space-saving reasons obviously) Any pointers?
[edit] SQL server agent is unavailable in SQL server express...
You cannot use the SQL Server agent in SQL Server Express.
The way I have done it before is to create a SQL Script, and then run it as a scheduled task each day, you could have multiple scheduled tasks to fit in with your backup schedule/retention. The command I use in the scheduled task is:
"C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE" -i"c:\path\to\sqlbackupScript.sql"
Eduardo Molteni had a great answer:
SQL Server Automated Backups
Using Windows Scheduled Tasks:
In the batch file
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -S
(local)\SQLExpress -i D:\dbbackups\SQLExpressBackups.sql
In SQLExpressBackups.sql
BACKUP DATABASE MyDataBase1 TO DISK = N'D:\DBbackups\MyDataBase1.bak'
WITH NOFORMAT, INIT, NAME = N'MyDataBase1 Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
BACKUP DATABASE MyDataBase2 TO DISK = N'D:\DBbackups\MyDataBase2.bak'
WITH NOFORMAT, INIT, NAME = N'MyDataBase2 Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
Just use this script to dynamically backup all databases on the server. Then create batch file according to the article. It is usefull to create two batch files, one for full backup a and one for diff backup. Then Create two tasks in Task Scheduler, one for full and one for diff.
-- // Copyright © Microsoft Corporation. All Rights Reserved.
-- // This code released under the terms of the
-- // Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
USE [master]
GO
/****** Object: StoredProcedure [dbo].[sp_BackupDatabases] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Microsoft
-- Create date: 2010-02-06
-- Description: Backup Databases for SQLExpress
-- Parameter1: databaseName
-- Parameter2: backupType F=full, D=differential, L=log
-- Parameter3: backup file location
-- =============================================
CREATE PROCEDURE [dbo].[sp_BackupDatabases]
#databaseName sysname = null,
#backupType CHAR(1),
#backupLocation nvarchar(200)
AS
SET NOCOUNT ON;
DECLARE #DBs TABLE
(
ID int IDENTITY PRIMARY KEY,
DBNAME nvarchar(500)
)
-- Pick out only databases which are online in case ALL databases are chosen to be backed up
-- If specific database is chosen to be backed up only pick that out from #DBs
INSERT INTO #DBs (DBNAME)
SELECT Name FROM master.sys.databases
where state=0
AND name=#DatabaseName
OR #DatabaseName IS NULL
ORDER BY Name
-- Filter out databases which do not need to backed up
IF #backupType='F'
BEGIN
DELETE #DBs where DBNAME IN ('tempdb','Northwind','pubs','AdventureWorks')
END
ELSE IF #backupType='D'
BEGIN
DELETE #DBs where DBNAME IN ('tempdb','Northwind','pubs','master','AdventureWorks')
END
ELSE IF #backupType='L'
BEGIN
DELETE #DBs where DBNAME IN ('tempdb','Northwind','pubs','master','AdventureWorks')
END
ELSE
BEGIN
RETURN
END
-- Declare variables
DECLARE #BackupName varchar(100)
DECLARE #BackupFile varchar(100)
DECLARE #DBNAME varchar(300)
DECLARE #sqlCommand NVARCHAR(1000)
DECLARE #dateTime NVARCHAR(20)
DECLARE #Loop int
-- Loop through the databases one by one
SELECT #Loop = min(ID) FROM #DBs
WHILE #Loop IS NOT NULL
BEGIN
-- Database Names have to be in [dbname] format since some have - or _ in their name
SET #DBNAME = '['+(SELECT DBNAME FROM #DBs WHERE ID = #Loop)+']'
-- Set the current date and time n yyyyhhmmss format
SET #dateTime = REPLACE(CONVERT(VARCHAR, GETDATE(),101),'/','') + '_' + REPLACE(CONVERT(VARCHAR, GETDATE(),108),':','')
-- Create backup filename in path\filename.extension format for full,diff and log backups
IF #backupType = 'F'
SET #BackupFile = #backupLocation+REPLACE(REPLACE(#DBNAME, '[',''),']','')+ '_FULL_'+ #dateTime+ '.BAK'
ELSE IF #backupType = 'D'
SET #BackupFile = #backupLocation+REPLACE(REPLACE(#DBNAME, '[',''),']','')+ '_DIFF_'+ #dateTime+ '.BAK'
ELSE IF #backupType = 'L'
SET #BackupFile = #backupLocation+REPLACE(REPLACE(#DBNAME, '[',''),']','')+ '_LOG_'+ #dateTime+ '.TRN'
-- Provide the backup a name for storing in the media
IF #backupType = 'F'
SET #BackupName = REPLACE(REPLACE(#DBNAME,'[',''),']','') +' full backup for '+ #dateTime
IF #backupType = 'D'
SET #BackupName = REPLACE(REPLACE(#DBNAME,'[',''),']','') +' differential backup for '+ #dateTime
IF #backupType = 'L'
SET #BackupName = REPLACE(REPLACE(#DBNAME,'[',''),']','') +' log backup for '+ #dateTime
-- Generate the dynamic SQL command to be executed
IF #backupType = 'F'
BEGIN
SET #sqlCommand = 'BACKUP DATABASE ' +#DBNAME+ ' TO DISK = '''+#BackupFile+ ''' WITH INIT, NAME= ''' +#BackupName+''', NOSKIP, NOFORMAT'
END
IF #backupType = 'D'
BEGIN
SET #sqlCommand = 'BACKUP DATABASE ' +#DBNAME+ ' TO DISK = '''+#BackupFile+ ''' WITH DIFFERENTIAL, INIT, NAME= ''' +#BackupName+''', NOSKIP, NOFORMAT'
END
IF #backupType = 'L'
BEGIN
SET #sqlCommand = 'BACKUP LOG ' +#DBNAME+ ' TO DISK = '''+#BackupFile+ ''' WITH INIT, NAME= ''' +#BackupName+''', NOSKIP, NOFORMAT'
END
-- Execute the generated SQL command
EXEC(#sqlCommand)
-- Goto the next database
SELECT #Loop = min(ID) FROM #DBs where ID>#Loop
END
And batch file can look like this:
sqlcmd -S localhost\myDB -Q "EXEC sp_BackupDatabases #backupLocation='c:\Dropbox\backup\DB\', #backupType='F'" >> c:\Dropbox\backup\DB\full.log 2>&1
and
sqlcmd -S localhost\myDB -Q "EXEC sp_BackupDatabases #backupLocation='c:\Dropbox\backup\DB\', #backupType='D'" >> c:\Dropbox\backup\DB\diff.log 2>&1
The advantage of this method is that you don't need to change anything if you add new database or delete a database, you don't even need to list the databases in the script. Answer from JohnB is better/simpler for server with one database, this approach is more suitable for multi database servers.
The folks at MSSQLTips have some very helpful articles, the one most relevant for this is "Automating SQL Server 2005 Express Backups and Deletion of Older Backup Files"
The basic approach is to set up two tasks using the Windows Task Scheduler. One task runs a TSQL script that generates separate backup files for all MSSQL databases (except TEMPDB) with the database name and a date/time stamp in the file name into a specified directory. The second task runs a VBScript script that goes through that directory and deletes all files with a .BAK extension that are more than 3 days old.
Both scripts require minor editing for your environment (paths, how long to keep those database dumps) but are very close to drop-in-and-run.
Note that there are possible security implications if you're sloppy with these or with directory permissions, since they are plain text files that will need to run with some level of privilege. Don't be sloppy.
We have used the combination of:
Cobian Backup for scheduling/maintenance
ExpressMaint for backup
Both of these are free. The process is to script ExpressMaint to take a backup as a Cobian "before Backup" event. I usually let this overwrite the previous backup file. Cobian then takes a zip/7zip out of this and archives these to the backup folder. In Cobian you can specify the number of full copies to keep, make multiple backup cycles etc.
ExpressMaint command syntax example:
expressmaint -S HOST\SQLEXPRESS -D ALL_USER -T DB -R logpath -RU WEEKS -RV 1 -B backuppath -BU HOURS -BV 3
You can create a backup device in server object, let us say
BDTEST
and then create a batch file contain following command
sqlcmd -S 192.168.1.25 -E -Q "BACKUP DATABASE dbtest TO BDTEST"
let us say with name
backup.bat
then you can call
backup.bat
in task scheduler according to your convenience