SansSQL: Automate

Sunday, February 5, 2012

T-SQL Query to change the datatype of multiple columns of single or multiple tables

There might be a situation where a person designed a database with a particular datatype for many tables and now you want to change the datatype to a different one for all those columns in a particular table or multiple tables due to various reasons.
Changing the datatype for a single table or five tables or 10 tables is a easy task, but when the tables list is in hundreds how easy is it do in the traditional way?
Below stored procedure gives you the flexibility of changing the datatype of multiple columns in a single or multiple tables at one go.

Things to note before running the scripts
  1. Backup your database 
  2. These scripts are provided AS IS without warranty of any kind.
Script:
CREATE PROC usp_ChangeColumnDatatype (@currentDataType nvarchar(25), 
   @DataTypeToSet nvarchar(50), 
   @ScanTables nvarchar(100), 
   @PrintCommandsOnly bit )

AS
SET NOCOUNT ON
DECLARE @ScanTables_Local nvarchar(100)
SET @ScanTables_Local = '''' + REPLACE(REPLACE(@ScanTables,',',''','''),' ','') + '''' 
IF @ScanTables = 'All'
BEGIN
CREATE TABLE #Temp (CommandsToExecute nvarchar(max))
INSERT INTO #temp SELECT 'ALTER TABLE ' + OBJECT_NAME(o.object_id) + 
    ' ALTER COLUMN ' + c.name + ' ' + @DataTypeToSet +
    CASE WHEN c.is_nullable = 0 THEN ' NOT NULL' ELSE ' NULL' END AS CommandsToExecute
FROM sys.objects o 
INNER JOIN sys.columns c ON o.object_id=c.object_id
INNER JOIN sys.types t ON c.system_type_id=t.system_type_id
WHERE o.type='u'
and t.name = @currentDataType
END

IF @ScanTables <> 'All'
BEGIN
CREATE TABLE #Temp_SpecificTables (CommandsToExecute nvarchar(max))

DECLARE @Cmd nvarchar(max)
SET @Cmd = 'INSERT INTO #Temp_SpecificTables  SELECT ''ALTER TABLE '' + OBJECT_NAME(o.object_id) + 
    '' ALTER COLUMN '' + c.name + ''' + @DataTypeToSet + ''' +
    CASE WHEN c.is_nullable = 0 THEN ''NOT NULL'' ELSE ''NULL'' END AS CommandsToExecute
FROM sys.objects o 
INNER JOIN sys.columns c ON o.object_id=c.object_id
INNER JOIN sys.types t ON c.system_type_id=t.system_type_id
WHERE o.type=''u''
and t.name = '''+@currentDataType+''' and OBJECT_NAME(o.object_id) in ('+ @ScanTables_Local + ')'
--PRINT @cmd
EXECUTE (@cmd)
END
if @PrintCommandsOnly = 'True' and @ScanTables = 'All'
BEGIN
SELECT * FROM #Temp
DROP TABLE #Temp
END

if @PrintCommandsOnly = 'False' and @ScanTables = 'All'
BEGIN
--SELECT * FROM #Temp
PRINT 'Changing of the datatypes of table(s) '+ @ScanTables +' from ' + @currentDataType + ' to '+ @DataTypeToSet + ' started at ' + CAST(GETDATE() AS varchar)
WHILE (SELECT COUNT(*) FROM #Temp) <> 0
BEGIN
DECLARE @varTemp nvarchar(max)
SELECT @varTemp = CommandsToExecute FROM #Temp
EXECUTE (@varTemp)
DELETE FROM #temp WHERE CommandsToExecute = @varTemp
END
DROP TABLE #Temp
PRINT 'Changing of the datatypes of table(s) '+ @ScanTables +' from ' + @currentDataType + ' to '+ @DataTypeToSet + ' ended at ' + CAST(GETDATE() AS varchar)
END

if @PrintCommandsOnly = 'True' and @ScanTables <> 'All'
BEGIN
SELECT * FROM #Temp_SpecificTables
DROP TABLE #Temp_SpecificTables
END

if @PrintCommandsOnly = 'False' and @ScanTables <> 'All'
BEGIN
--SELECT * FROM #Temp_SpecificTables
PRINT 'Changing of the datatypes of table(s) '+ @ScanTables_Local +' from ' + @currentDataType + ' to '+ @DataTypeToSet + ' started at ' + CAST(GETDATE() AS varchar)
WHILE (SELECT COUNT(*) FROM #Temp_SpecificTables) <> 0
BEGIN
DECLARE @varTemp_SpecificTables nvarchar(max)
SELECT @varTemp_SpecificTables = CommandsToExecute FROM #Temp_SpecificTables
EXECUTE (@varTemp_SpecificTables)
DELETE FROM #Temp_SpecificTables WHERE CommandsToExecute = @varTemp_SpecificTables
END
DROP TABLE #Temp_SpecificTables
PRINT 'Changing of the datatypes of table(s) '+ @ScanTables_Local +' from ' + @currentDataType + ' to '+ @DataTypeToSet + ' ended at ' + CAST(GETDATE() AS varchar)
END
SET NOCOUNT OFF
GO

Usage:
EXEC usp_ChangeColumnDatatype @currentDataType = 'nvarchar', 
         @DataTypeToSet = 'varchar(50)', 
         @ScanTables = 'Table_1,Table_2', --Table1, Table2,Table3 or ALL
         @PrintCommandsOnly = 'FALSE' -- TRUE - Will print the commands or FALSE - Will execute the commands.

Sunday, August 14, 2011

Looping through SQL Servers using SSIS or Dynamically build connection to multiple SQL Servers

Consider you are giver a task of gathering information from multiple servers. What are the different ways you can automate this?
  1. Create linked servers in each server pointing to your central repository
  2. Create Separate SSIS package in each servers which loads data to your central repository
  3. Create one SSIS package with multiple data sources and duplicate the tasks for each data source.
  4. Create one SSIS package which dynamically builds connection to each server and does the data loading tasks.
If you choose an option between 1 and 3 , then  you will have to do some extra work for gathering the server information when there are new servers added to your environment.
If you choose the 4th option then also you will have some extra work but it is very small and easy when compared to the first 3 options. Here you need to just add the new Server Names to the table and that is all and everything else will be taken care by the SSIS package.
In this post I am going to explain how to create a SSIS package which loops through multiple SQL server and gathers information  by building the connection to those servers dynamically.
  1. Open “Microsoft Visual Studio”
  2. Create a new “Integration Services Project”
  3. Create a SSIS Package
  4. Create 2 Connection Managers, 1 for the source (which will be set dynamically for each iteration of the loop)  and the other for destination (which will remain constant, in other terms your Central Repository)
  5. Store All your Server Names in a table preferably in the Central Repository (Destination Connection)
  6. Add 2 variables
  7.     a. Name: ConnectionVariable (A name of your choice)
            Scope: Package
            Type: Object
            Value: System.Object
        b. Name: ServerName  (A name of your choice)
            Scope: Package
            Type: String
            Value: A Valid Server Name

  8. Add an "Execute SQL Task" with SQL Statement like "select FullName from dba..tbl_ListOfServers".
  9. Set the result set to Full Result Set.
  10. On the Result Set page, Add a Result 
  11. Set Result Name "0" and assign it to your Object variable (In our case it is “ConnectionVariable”).
  12. Now add a “Foreach Loop Container” 
  13. Connect it from the “Execute SQL Task”
  14. Inside the “Foreach Loop Container” , add the required “Data Flow Task”
  15. Now Right-Click on the “Foreach Loop Container” and click on “Edit”
  16. Now Go to “Collection” page and Set “Enumerator” to “Foreach ADO Enumerator” and “Enumerator Configuration ” to the Object Variable(In Our Case “ConnectionVariable”) and Set “Enumeration Mode” to “Rows in the First Table”
  17. Now go to the “Variable Mapping” page and Choose the “String Variable” (In our case it is “ServerName”) and set the Index=0
  18. Now, in the “Data Flow Task” add a “OLE DB Source” (Dynamic Connection) and connect it down to a “OLE DB Destination” (which will be your Central Repository).
  19. Now Select the Source Connection Manager (In Our Case it is “Source”) and Right-Click on this Source and choose “Properties”.
  20. Expand the “Expressions” Option and click on the browse button (…)
  21. Now in the “Property Expression Editor”, Choose the property “ServerName” and click on browse button (…). Now choose the String Variable (in our case “ServerName”) and Drag and Drop this variable into the “Expression” box and click “OK” and “OK”.


Now when the package runs, the “Execute SQL Task” will read the list of servers and stored in the table you specified and the “Foreach loop” will iterate over each record in that table, running the “Data Flow Task” each time while each time, the ServerName property of the Source Connection in the data flow will get a new value.

This article is also available in pdf format for downloading.
Please Click here to get your copy.

Sunday, August 7, 2011

Finding space usage of database files

DBA's are required to watch the space usage of database files in order to take preventive measures of future failures with respect to database full issues.
This will be usually required when there is a bulk activity happening on a database.
To do this make use of the below stored procedure.
Create this SP in a database and execute it in regular intervals to get the latest status of the database files.
This can be used to view the space usage of all the database files or for a particular threshold value.
Use master
GO
Create proc sp_SpaceUsageReport (@Threshold int=80)
as

CREATE TABLE tempdb..SpaceUsage (
  DatabaseName nvarchar(100)
 ,LogicalFileName nvarchar(500)
 ,FileType nvarchar(10)
 ,PhysicalFileLocation nvarchar(500)
 ,[FileSize (MB)] float
 ,[SpaceUsed (MB)] float
 ,[FreeSpace (MB)] float
 ,[% Used] AS 100-(([FileSize (MB)]-[SpaceUsed (MB)])/[FileSize (MB)])*(100)
 ,[% Free]  AS (([FileSize (MB)]-[SpaceUsed (MB)])/[FileSize (MB)])*(100) )

If (SELECT Convert(varchar(1),(SERVERPROPERTY('ProductVersion')))) = 8
BEGIN
EXEC sp_MSforeachdb 'USE [?];
INSERT INTO tempdb..SpaceUsage(DatabaseName
           ,LogicalFileName
           ,FileType
           ,PhysicalFileLocation   
           ,[FileSize (MB)]
           ,[SpaceUsed (MB)]
           ,[FreeSpace (MB)])
SELECT DB_NAME() AS DatabaseName
       ,name AS LogicalFileName
       ,FileType = CASE WHEN FILEPROPERTY(name,''IsLogFile'')=0 THEN ''Data File'' WHEN FILEPROPERTY(name,''IsLogFile'')=1 THEN ''Log File'' END
       ,filename AS PhysicalFileLocation
       ,CONVERT(float,ROUND(size/128.000,2)) AS [FileSize (MB)]
       ,CONVERT(float,ROUND(FILEPROPERTY(name,''SpaceUsed'')/128.000,2)) AS [SpaceUsed (MB)]
       ,CONVERT(float,ROUND((size-FILEPROPERTY(name,''SpaceUsed''))/128.000,2)) AS [FreeSpace (MB)]
FROM dbo.sysfiles
ORDER BY FileType '
END

If (SELECT Convert(varchar(1),(SERVERPROPERTY('ProductVersion'))))<> 8
BEGIN
EXEC sp_MSforeachdb 'USE [?];
INSERT INTO tempdb..SpaceUsage(DatabaseName
           ,LogicalFileName
           ,FileType
           ,PhysicalFileLocation
           ,[FileSize (MB)]
           ,[SpaceUsed (MB)]
           ,[FreeSpace (MB)])
SELECT DB_NAME() AS DatabaseName
            ,name AS LogicalFileName
            ,FileType = CASE WHEN type_desc =''Rows'' THEN ''Data File'' WHEN type_desc =''LOG'' THEN ''Log File'' END
            ,physical_name AS PhysicalFileLocation
            ,CONVERT(float,ROUND(size/128.000,2)) AS [FileSize (MB)]
            ,CONVERT(float,ROUND(FILEPROPERTY(name,''SpaceUsed'')/128.000,2)) AS [SpaceUsed (MB)]
            ,CONVERT(float,ROUND((size-FILEPROPERTY(name,''SpaceUsed''))/128.000,2)) AS [FreeSpace (MB)]
FROM sys.database_files
ORDER BY FileType'
END

if (Select COUNT(*) from tempdb..SpaceUsage where [% Used]>@Threshold)>0
Begin
/* -- Enable this Content if you want to send email.

DECLARE @table  NVARCHAR(MAX),@Subject Nvarchar(500) ;
Set @Subject='[SQLAlert] Database Files Space Threshold exceeded Report from ' + CAST(@@SERVERNAME as nvarchar)
SET @table =
    N'<H1>Threshold Value for this Report is '+CAST(@Threshold AS nvarchar)+' Percentage. </H1>' +
    N'<table border="1">' +
    N'<tr><th>DatabaseName</th><th>FileType</th><th>PhysicalFileLocation</th><th>FileSize (MB)</th><th>% Used</th></tr> ' +
    CAST ( ( Select td=DatabaseName, '',td=FileType, '',td=PhysicalFileLocation,'',td=CAST([FileSize (MB)] as nvarchar),'',td=CAST([% Used] AS nvarchar) from tempdb..SpaceUsage where [% Used]>@Threshold
              FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) )    +
    N'</table>' ;

EXEC msdb.dbo.sp_send_dbmail @profile_name='DatabaseMail', --Change to your Profile Name
      @recipients='sandeshsegu@SansSQL.com', --Put the email address of those who want to receive the e-mail
    @subject = @Subject,
    @body = @table,
    @body_format = 'HTML' ;  
*/   

select * from  tempdb..SpaceUsage where [% Used]>@Threshold                                 
End

DROP TABLE tempdb..SpaceUsage

To send an email of this report you need to
  1. Configure Database Mail option. To configure Database mail option, follow this post.
  2. Uncomment the below content in the SP.
/* -- Enable this Content if you want to send email.

DECLARE @table  NVARCHAR(MAX),@Subject Nvarchar(500) ;
Set @Subject='[SQLAlert] Database Files Space Threshold exceeded Report from ' + CAST(@@SERVERNAME as nvarchar)
SET @table =
    N'<H1>Threshold Value for this Report is '+CAST(@Threshold AS nvarchar)+' Percentage. </H1>' +
    N'<table border="1">' +
    N'<tr><th>DatabaseName</th><th>FileType</th><th>PhysicalFileLocation</th><th>FileSize (MB)</th><th>% Used</th></tr> ' +
    CAST ( ( Select td=DatabaseName, '',td=FileType, '',td=PhysicalFileLocation,'',td=CAST([FileSize (MB)] as nvarchar),'',td=CAST([% Used] AS nvarchar) from tempdb..SpaceUsage where [% Used]>@Threshold
              FOR XML PATH('tr'), TYPE
    ) AS NVARCHAR(MAX) )    +
    N'</table>' ;

EXEC msdb.dbo.sp_send_dbmail @profile_name='DatabaseMail', --Change to your Profile Name
      @recipients='sandeshsegu@SansSQL.com', --Put the email address of those who want to receive the e-mail
    @subject = @Subject,
    @body = @table,
    @body_format = 'HTML' ;  
*/    

Usage of this SP:
This SP expects a parameter called @Threshold
If you specify the @Threshold=0 then, this SP will give space usage details of all the database files.
Exec sp_SpaceUsageReport @Threshold=0

If you specify the @Threshold=80 then, this SP will give space usage details of those database files which exceeds the threshold 80 percent.
Exec sp_SpaceUsageReport @Threshold=80

Thursday, April 7, 2011

T-SQL Query to find the SQL Server Protocols Status

Here is a T-SQL Query that I have developed to get the status of the SQL Server Protocols.
This query reads data from the registry.
DECLARE @InstanceName nvarchar(50)
DECLARE @value VARCHAR(100)
DECLARE @value_Out VARCHAR(100)
DECLARE @RegKey_InstanceName nvarchar(500)
DECLARE @RegKey nvarchar(500)

SET @InstanceName=CONVERT(nVARCHAR,isnull(SERVERPROPERTY('INSTANCENAME'),
'MSSQLSERVER'))

CREATE TABLE #SQLServerProtocols
(ProtocolName nvarchar(25),
Value nvarchar(10),
Data bit)

if(SELECT Convert(varchar(1),(SERVERPROPERTY('ProductVersion'))))<>8
BEGIN
SET @RegKey_InstanceName='SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL'

EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey_InstanceName,
  @value_name = @InstanceName,
  @value = @value OUTPUT

SET @RegKey='SOFTWARE\Microsoft\Microsoft SQL Server\'+@value+'\MSSQLServer\SuperSocketNetLib\Sm'
Insert into #SQLServerProtocols (Value,Data)
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'Enabled'
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'DisplayName',
  @value = @value_Out OUTPUT
UPDATE #SQLServerProtocols set ProtocolName=@value_Out 
where ProtocolName is null


SET @RegKey='SOFTWARE\Microsoft\Microsoft SQL Server\'+@value+'\MSSQLServer\SuperSocketNetLib\Np'
Insert into #SQLServerProtocols (Value,Data)
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'Enabled'
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'DisplayName',
  @value = @value_Out OUTPUT
UPDATE #SQLServerProtocols set ProtocolName=@value_Out
where ProtocolName is null

SET @RegKey='SOFTWARE\Microsoft\Microsoft SQL Server\'+@value+'\MSSQLServer\SuperSocketNetLib\TCP'
Insert into #SQLServerProtocols (Value,Data)
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'Enabled'
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'DisplayName',
  @value = @value_Out OUTPUT
UPDATE #SQLServerProtocols set ProtocolName=@value_Out 
where ProtocolName is null

SET @RegKey='SOFTWARE\Microsoft\Microsoft SQL Server\'+@value+'\MSSQLServer\SuperSocketNetLib\Via'
Insert into #SQLServerProtocols (Value,Data)
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'Enabled'
EXECUTE xp_regread
  @rootkey = 'HKEY_LOCAL_MACHINE',
  @key = @RegKey,
  @value_name = 'DisplayName',
  @value = @value_Out OUTPUT
UPDATE #SQLServerProtocols set ProtocolName=@value_Out 
where ProtocolName is null
END

SELECT ProtocolName, IsEnabled=CASE WHEN Data=1 THEN 'Enabled' 
ELSE 'Disabled' END FROM #SQLServerProtocols

DROP TABLE #SQLServerProtocols

Download this script from here.

Sunday, March 20, 2011

Automating SQL Server Express Backups

As we all know that many of the third party applications uses SQL Server Express Edition to store their backend data. And also these application will be used in Live environments which requires backing up of the databases to recover data during a disaster.
Since there is no SQL Server agent in Express Edition, we cannot schedule SQL Backups or any other DB Maintenance activities using SQL Scheduler. So for this purpose, we have to make use of the windows scheduler.
For Automating the backup process, i have developed the below query which can be used for multiple purpose and can be scheduled using windows scheduler as well as SQL Agent.

Script
:
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_BackupDatabases]') AND type in (N'P', N'PC'))
BEGIN
PRINT 'Stored Procedure "sp_BackupDatabases" already exists in the database. Dropping the SP to create a newer Version.'
DROP PROCEDURE [dbo].[sp_BackupDatabases]
END
GO

CREATE PROC sp_BackupDatabases (@BackupDBType nvarchar(10)='Help', @DBName nvarchar(max)=NULL, @BackupPath nvarchar(max)=NULL )
AS
/*
Author: Sandesh Segu
Website: http://www.SansSQL.com
*/
SET NOCOUNT ON

DECLARE @DateTime nvarchar(25)
SET @DateTime=LEFT(REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(30),GETDATE(),120),':',''),'-',''),' ',''),12)

IF @BackupDBType not in ('ALL','System','User','Specific','Help')
BEGIN
RAISERROR ('Incorrect Parameter Value Passed. @BackupDBType Parameters should be ''ALL'',''System'',''User'',''Specific''',16,1)
END

IF @BackupDBType<> 'HELP' and @BackupPath IS NULL
BEGIN
RAISERROR ('Specify the path to backup databases. @BackupPath must be specified',16,1)
END
IF (RIGHT(@BackupPath,1))<>'\'
BEGIN
Select @BackupPath=@BackupPath+'\'
END
ELSE
BEGIN
Select @BackupPath=@BackupPath
END

IF @BackupDBType='Help' AND @DBName IS NULL AND @BackupPath IS NULL
BEGIN
Print 'Usage of this Stored Proc can be in any of the below format.'
Print '-------------------------------------------------------------------------'
Print '1. To Backup All Databases in a instance'
Print '   Exec sp_BackupDatabases @BackupDBType = ''ALL'', @BackupPath = ''C:\Backup''' + Char(10)
Print '2. To Backup only System Databases in a instance'
Print '   Exec sp_BackupDatabases @BackupDBType = ''System'', @BackupPath = ''C:\Backup''' + Char(10)
Print '3. To Backup only User Databases in a instance'
Print '   Exec sp_BackupDatabases @BackupDBType = ''User'', @BackupPath = ''C:\Backup''' + Char(10)
Print '4. To Backup specific (One) Database(s) in a instance'
Print '   Exec sp_BackupDatabases @BackupDBType = ''Specific'', @DBName = ''AdventureWorks'', @BackupPath = ''C:\Backup''' + Char(10)
Print '5. To Backup specific (more than One) Database(s) in a instance'
Print '   Exec sp_BackupDatabases @BackupDBType = ''Specific'', @DBName = ''AdventureWorks,master,msdb'', @BackupPath = ''C:\Backup'''
Print '-------------------------------------------------------------------------'
END

IF exists (select * from sys.objects where name='BackupDatabases')
DROP TABLE BackupDatabases
CREATE TABLE BackupDatabases
(DBName nvarchar(100),
DatabaseID int,
[BackupStatement] nvarchar(max))

IF @BackupDBType='ALL' AND @DBName IS NULL AND @BackupPath IS NOT NULL
BEGIN
INSERT INTO BackupDatabases
SELECT name,database_id, '' FROM sys.databases WHERE name <>'tempdb'
END

IF @BackupDBType='System' AND @DBName IS NULL AND @BackupPath IS NOT NULL
BEGIN
INSERT INTO BackupDatabases
SELECT name,database_id, '' FROM sys.databases WHERE name in ('master', 'model','msdb')
END

IF @BackupDBType='User' AND @DBName IS NULL AND @BackupPath IS NOT NULL
BEGIN
INSERT INTO BackupDatabases
SELECT name,database_id, '' FROM sys.databases WHERE database_id>4
END

IF @BackupDBType='Specific' AND @DBName IS NULL
BEGIN
RAISERROR ('Specify the Database Name(s) to Backup. @DBName must be specified.',16,1)
END

IF @BackupDBType='Specific' AND @DBName IS NOT NULL AND @BackupPath IS NOT NULL
BEGIN
DECLARE @DelimiterPos int
-- Find the first comma
SET @DelimiterPos = PATINDEX( '%,%', @DBName)
-- If a delimiter was found, @DelimiterPos will be > 0.
WHILE @DelimiterPos > 0
BEGIN
-- Insert the value between the start of the string and the first delimiter, into the table variable.
INSERT INTO BackupDatabases
SELECT name,database_id, '' FROM sys.databases WHERE name in (SELECT CAST(LTRIM(RTRIM((SUBSTRING(@DBName, 1, @DelimiterPos -1)))) AS nvarchar      ))                  
-- Trim the string of the first value and delimiter.
SET @DBName = SUBSTRING(@DBName, @DelimiterPos +1, LEN(@DBName) - @DelimiterPos)
                       
-- Look for the next delimiter in the string.
SET @DelimiterPos = PATINDEX( '%,%', @DBName)
END
INSERT INTO BackupDatabases
SELECT name,database_id, '' FROM sys.databases WHERE name in (SELECT CAST(LTRIM(RTRIM((@DBName))) AS nvarchar))
END

UPDATE BackupDatabases SET BackupStatement= 'Print ''Backup of Database '+DBName+' Started''; Backup Database ['+DBName+'] TO DISK='''+@BackupPath+DBName+'_Backup_'+@DateTime+'.bak'' WITH INIT, STATS=10'
Print 'The Requested database(s) are being backed up to the location "'+@BackupPath+'"'
WHILE (Select COUNT(*) from BackupDatabases)>0
BEGIN
DECLARE @BackupStatement nvarchar(max)
SELECT @BackupStatement= [BackupStatement] FROM BackupDatabases
Exec sp_executesql @BackupStatement
Delete from BackupDatabases where [BackupStatement]=@BackupStatement
END
DROP TABLE BackupDatabases

SET NOCOUNT OFF
GO

Usage:
Usage of this Stored Proc can be in any of the below format.
-------------------------------------------------------------------------
1. To Backup All Databases in a instance
   Exec sp_BackupDatabases @BackupDBType = 'ALL', @BackupPath = 'C:\Backup'

2. To Backup only System Databases in a instance
   Exec sp_BackupDatabases @BackupDBType = 'System', @BackupPath = 'C:\Backup'

3. To Backup only User Databases in a instance
   Exec sp_BackupDatabases @BackupDBType = 'User', @BackupPath = 'C:\Backup'

4. To Backup specific (One) Database(s) in a instance
   Exec sp_BackupDatabases @BackupDBType = 'Specific', @DBName = 'AdventureWorks', @BackupPath = 'C:\Backup'

5. To Backup specific (more than One) Database(s) in a instance
   Exec sp_BackupDatabases @BackupDBType = 'Specific', @DBName = 'AdventureWorks,master,msdb', @BackupPath = 'C:\Backup'

To Delete the old backups I use the below query.
DECLARE @TwoDaysOld VARCHAR(50)
Set @TwoDaysOld=CAST(DATEADD(d, -2, GETDATE()) AS VARCHAR)
Select @TwoDaysOld
Exec master.dbo.xp_delete_file 0,N'C:\Backups\',N'bak',@TwoDaysOld
This will delete any .bak files in the given location which are older than 2 days.

So after creating the sp_BackupDatabases stored proc, if we want to schedule the backups using windows scheduler than we have create a batch file (.bat file) which will be called in the windows scheduler at the scheduled time.
sqlcmd -S(local)\SQLEXPRESS -E -Q"DECLARE @TwoDaysOld VARCHAR(50) Set @TwoDaysOld=CAST(DATEADD(d, -2, GETDATE()) AS VARCHAR)
Exec master.dbo.sp_BackupDatabases @BackupDBType = 'User', @BackupPath = 'C:\Backup'
Exec master.dbo.xp_delete_file 0,N'D:\Backups\',N'bak',@TwoDaysOld"

Scripts can be downloaded from the below locations

Ads