T-SQL Backup Code

  • Our environment is a little weird. Instead of just using a maintenance job or backing up dbs to one root folder, we have to create a structure mimicking the de-dup structure our corporate office uses. What that means is we have a structure like this:

    NASName

    DB1

    20160801_FULL

    20160802

    20160803

    ...

    20160807_FULL

    DB2

    20160801_FULL

    20160802

    20160803

    ...

    20160807_FULL

    The folders with _FULL have the full backup of the week. The folders without the _FULL have the differentials. Transaction logs are in both folders. The individual folders are named after the date the backup is being taken on.

    There are two / three jobs on each server. The first job runs in the morning to create the folders. The second job does the FULL/DIFFERENTIAL backups. The third job creates transaction log backups for those databases in FULL recovery mode on a couple of servers, but not all servers.

    The job in question is the folder job. It works great for creating the folder structure exactly as we need it. The problem I'm running into is how to use a TRY...CATCH to send us email notifications when the job fails. I deliberately set up a failure scenario in the code. The job failed, sent a failure notification, but did not hit the CATCH block to send the email with the error.

    I haven't really used TRY...CATCH a lot. Could someone look at the below code and let me know what I'm missing? I plan to apply the same logic to the backup jobs as soon as I have it corrected in the folder jobs.

    BEGIN TRY

    ---Create backup folders for the day.

    --SET QUOTED_IDENTIFIER OFF;

    IF (SELECT OBJECT_ID('tempdb..#DBResultSet')) IS NOT NULL

    DROP TABLE #DBResultSet;

    IF (SELECT OBJECT_ID('tempdb..#BackupResultSet')) IS NOT NULL

    DROP TABLE #BackupResultSet;

    --DROP temp tables if they exist

    CREATE TABLE #DBResultSet (Directory VARCHAR(400), Folder VARCHAR(50));

    CREATE TABLE #BackupResultSet (DailyFolder VARCHAR(50));

    --Create temp tables

    DECLARE @BaseFolder VARCHAR(128),@DBMainBackupFolder VARCHAR(200),@DatabaseDailyFolder VARCHAR(256),@DbName SYSNAME, @TodayDate CHAR(8), @FullOrDiff BIT,

    @MySQL VARCHAR(500);

    --Set up variables. BackupFolder is the

    -- Input parameters needed FROM the user.

    SET @BaseFolder = '\\Myas\backup\share\';

    SELECT @TodayDate = CONVERT(CHAR(8),GETDATE(),112);

    SELECT @FullOrDiff = CASE WHEN DATEPART(dw,@TodayDate) = 3 THEN 1 ELSE 0 END;

    INSERT INTO #DBResultSet (Folder)

    EXEC master.sys.xp_subdirs @BaseFolder;

    DECLARE Db CURSOR FOR

    SELECT name FROM sys.databases

    WHERE name NOT IN ('tempdb') AND name NOT LIKE 'Report_%'

    AND name NOT LIKE '%ProdCopy'

    AND state_desc = 'ONLINE' AND replica_id IS NULL AND source_database_ID IS NULL;

    OPEN Db;

    FETCH NEXT FROM Db INTO @DbName;

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SELECT @DBMainBackupFolder = @BaseFolder + '\' + @DbName ;

    -- Dynamically create a base folder for each database.

    SELECT @DatabaseDailyFolder = CASE @FullOrDiff WHEN 1 THEN @BaseFolder + '\' + @DbName + '\' + @TodayDate + '_FULL' + '\'

    WHEN 0 THEN @BaseFolder + '\' + @DbName + '\' + @TodayDate + '\'

    END;

    -- Dynamically create the day's backup folder for each database.

    SET @MySQL = 'INSERT INTO #BackupResultSet (DailyFolder) EXEC master.dbo.xp_subdirs '' + @DBMainBackupFolder + '';';

    --Get list of existing daily folders

    EXEC (@MySQL);

    IF (SELECT directory FROM #DBResultSet WHERE directory = @DBMainBackupFolder) IS NULL

    EXEC master.sys.xp_create_subdir @DBMainBackupFolder;

    --Check for main DB folder

    IF (SELECT DailyFolder FROM #BackupResultSet WHERE DailyFolder = @DatabaseDailyFolder AND DbName = @DBName) IS NULL

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder; --Error introduced in line above.

    --Check for daily bakup folder

    --SELECT @DBName AS DBName, @DBMainBackupFolder AS BackupDirectory, @DatabaseDailyFolder AS DBFolder, @FullOrDiff AS FullOrDiff, @MySQL AS SQLCommand; /* For troubleshooting */

    --SELECT * FROM #DBResultSet; /* For troubleshooting */

    --SELECT * FROM #BackupResultSet; /* For troubleshooting */

    TRUNCATE TABLE #BackupResultSet;

    FETCH NEXT FROM Db INTO @DbName;

    END

    -- Clean up

    CLOSE Db;

    DEALLOCATE Db;

    END TRY

    BEGIN CATCH

    DECLARE @ErrorMessage NVARCHAR(4000), @ErrorSeverity INT, @ErrorState INT, @ErrorSubject VARCHAR(50);

    SET @ErrorSubject = 'FAILURE: DBA_CreateBackupFolder Job on ' + @@SERVERNAME

    SET @ErrorMessage = 'Dear Admin,

    Due to some error, the DBA_CreateBackupFolder job on Server ' + @@Servername +

    ' has failed.

    '

    + 'Given below is the error message, state and severity.

    ErrorMessage : ' + ERROR_MESSAGE()

    + '

    ErrorState : ' + CONVERT(VARCHAR(7),@ErrorState)

    + '

    ErrorSeverity : ' + CONVERT(VARCHAR(7),@ErrorSeverity)

    ROLLBACK TRANSACTION;

    EXEC msdb.dbo.sp_send_dbmail @profile_name='MyProfile@email.com',

    @recipients='DBATeam@email.com',

    @subject=@ErrorSubject,

    @body= @ErrorMessage,

    @body_format = 'Text';

    END CATCH;

    GO

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Wow, those double quotes are really throwing the SQL parser off, makes it difficult to read.

    It's probably obvious, but I didn't see it. Which line of code is (deliberately) creating the error and what is the error?


  • Phil Parkin (8/9/2016)


    Wow, those double quotes are really throwing the SQL parser off, makes it difficult to read.

    It's probably obvious, but I didn't see it. Which line of code is (deliberately) creating the error and what is the error?

    Whoops. Double quotes removed for readability.

    The error wasn't in the code I originally posted because I grabbed the wrong query window. I've put it back into the second temp table SELECT where it's about to execute the subdir command. Also commented it.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • So it's this row that generates the error?

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder;

    If so, I think you might have to modify your code to capture the execution status of the xp and then, based on the status, throw the appropriate error.


  • Phil Parkin (8/9/2016)


    So it's this row that generates the error?

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder;

    If so, I think you might have to modify your code to capture the execution status of the xp and then, based on the status, throw the appropriate error.

    Actually, it should be failing on the IF statement right above it.

    IF (SELECT DailyFolder FROM #BackupResultSet WHERE DailyFolder = @DatabaseDailyFolder AND DbName = @DBName) IS NULL

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder; --Error introduced in line above.

    --Check for daily bakup folder

    DbName doesn't exist as a column in #BackupResultSet. And it calls that out in the message results I'm getting. But maybe SQL is only parsing that problem when it executes the stored proc... I'll take a look at that.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Brandie Tarvin (8/11/2016)


    Phil Parkin (8/9/2016)


    So it's this row that generates the error?

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder;

    If so, I think you might have to modify your code to capture the execution status of the xp and then, based on the status, throw the appropriate error.

    Actually, it should be failing on the IF statement right above it.

    IF (SELECT DailyFolder FROM #BackupResultSet WHERE DailyFolder = @DatabaseDailyFolder AND DbName = @DBName) IS NULL

    EXEC master.sys.xp_create_subdir @DatabaseDailyFolder; --Error introduced in line above.

    --Check for daily bakup folder

    DbName doesn't exist as a column in #BackupResultSet. And it calls that out in the message results I'm getting. But maybe SQL is only parsing that problem when it executes the stored proc... I'll take a look at that.

    OK, you are right ... the invalid column name error is thrown before the statement is even executed. So it's not a run-time error as such and that's why the TRY CATCH block does not capture it.

    If you have Intellisense enabled and set to underline errors, DbName should be underlined for you at design time.


Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic. Login to reply