Vous en rêviez ? Je l’ai faite pour vous… De quoi vous simplifier la vie avec une procédure pour sauvegarder toutes vos bases de données d’un seule coup !
Cette procédure permet de sauvegarder toutes les bases d’une instance en choisissant d’exclure :
1) les bases systèmes master, model et msdb (tempdb n’est pas sauvegardable)
[paramètre @ONLY_USER_DB bit]
2) d’exclure une liste de base de votre choix, données sous la forme d’un document XML dont la forme est contrôlée
[paramètre @EXCLUDE_DB xml]
Et d’indiquer différents autres paramètres tels que :
[paramètre @BACKUP_TYPE char(1)]
[paramètre @FILE_PATH nvarchar(256)]
[paramètre @FILE_NAME nvarchar(128)]
[paramètre @FILE_EXT nvarchar(8)]
[paramètre @FILE_DATE bit]
[paramètre @FILE_TIME bit]
[paramètre @UTC_DATETIME bit]
[paramètre @COMPRESSION]
[paramètre @FILE_FORMAT bit]
En voici le code, pleinement documenté :
CREATE PROCEDURE dbo.P_BACKUP_ALL_DATABASE @BACKUP_TYPE CHAR(1), -- type of backup F for FULL, D for Differential, T for Logs (transactional) @FILE_PATH NVARCHAR(256), -- path to store the backups. If NULL store the backups in the défault backup path @FILE_EXT NVARCHAR(8) , -- if NULL, BAK for Full, DIF for Differential and TRN for Logs (transactions) @FILE_NAME NVARCHAR(128), -- if NULL create one file per database to be backuped, if valued stacks all the backups in only one nammed file @FILE_DATE BIT, -- if 1 add date in file name @FILE_TIME BIT, -- if 1 add time in file name @FILE_FORMAT BIT, -- if 1 format the existing file @UTC_DATETIME BIT, -- if 0 datetime is in local time (by default, UTC datetime) @ONLY_USER_DB BIT, -- if 1 backup only user's databases @EXCLUDE_DB XML, -- list of databases to exclude in the form of '<dbs><db>database_name1</db><db>database_name2</db></dbs>' @COMPRESSION BIT -- if one add compression AS /****************************************************************************** * MODULE : BACKUP * * NATURE : PROCEDURE * * OBJECT : dbo.P_BACKUP_ALL_DATABASE * * CREATE : 2018-05-29 * * VERSION : 1 * ******************************************************************************* * Frédéric BROUARD - alias SQLpro - SARL SQL SPOT - SQLpro@sqlspot.com * * Architecte de données : expertise, audit, conseil, formation, modélisation * * tuning, sur les SGBD Relationnels, le langage SQL, MS SQL Server/PostGreSQL * * blog: http://mssqlserver.fr website: http://sqlpro.developpez.com * * Most Valuable Professional - MVP - SQL Server (data platform) depuis 2004 * ******************************************************************************* * PURPOSE : backup all databases in an instance * ******************************************************************************* * INPUTS : * * @BACKUP_TYPE CHAR(1) -- type of backup F for FULL, D for * * -- Differential, T for Logs (transactional) * * @FILE_PATH NVARCHAR(256) -- path to store the backups. If NULL store * * -- the backups in the défault backup path * * @FILE_EXT NVARCHAR(8) -- if NULL BAK for Full DIF for Differential * * -- and TRN for Logs (transactions) * * @FILE_NAME NVARCHAR(128) -- if NULL create one file per database to * * -- be backuped, if valued stacks all the * * -- backups in the only file you nammed * * @FILE_DATE BIT -- if 1 add date in file name * * @FILE_TIME BIT -- if 1 add time in file name * * @FILE_FORMAT BIT -- if 1 format the existing file * * @UTC_DATETIME BIT -- if 0 datetime is in local time, if 1 UTC * * @ONLY_USER_DB BIT -- if 1 backup only user's databases * * @EXCLUDE_DB XML -- list of databases to exclude. Patterne is * * '<dbs> * * <db>database_name1</db> * * <db>database_name2</db> * * ... * * </dbs>' * * @COMPRESSION BIT -- if one add compression * ******************************************************************************* * OUPUT : none * ******************************************************************************* * RUNNABLE : version 2012 and superior * * must have sysdamin role or equivalent (for of logging errors) * ******************************************************************************* * SAMPLE : * * EXEC dbo.P_BACKUP_ALL_DATABASE * * @BACKUP_TYPE = 'F', * * @FILE_PATH = 'C:\DATA', * * @FILE_EXT = NULL, * * @FILE_NAME = NULL, * * @FILE_DATE = 1, * * @FILE_TIME = 1, * * @FILE_FORMAT = 1, * * @UTC_DATETIME = 1, * * @ONLY_USER_DB = 1, * * @EXCLUDE_DB = N'<dbs> * * <db>ReportServer$SQL2016FBIN2</db> * * <db>ReportServer$SQL2016FBIN2TempDB</db> * * </dbs>', * * @COMPRESSION = 1 * ******************************************************************************/ SET NOCOUNT ON; -- verify if @BACKUP_TYPE is F, D or T IF @BACKUP_TYPE COLLATE Latin1_General_CI_AS NOT IN ('F', 'D', 'T') BEGIN RAISERROR('The backup type "%s" is not a valid one. Must be "F" for FULL, "D" for Differentiel or "T" for Transactional (logs).', 16, 1, @BACKUP_TYPE); RETURN; END; --verify if @FILE_EXT is composed only of letters, figures and underscore IF NOT @FILE_EXT COLLATE Latin1_General_CI_AS LIKE REPLICATE('[A-Z0-9_]', LEN(@FILE_EXT)) OR @FILE_EXT = '' BEGIN RAISERROR('The file extension %s is not a valid one. Must be composed of letters, figure and underscore.', 16, 1, @FILE_EXT); RETURN; END; --verify if @FILE_EXT is composed only of letters, figures and underscore IF NOT @FILE_NAME COLLATE Latin1_General_CI_AS LIKE REPLICATE('[A-Z0-9_]', LEN(@FILE_NAME)) OR @FILE_NAME = '' BEGIN RAISERROR('The file name %s is not a valid one. Must be composed of letters, figure and underscore.', 16, 1, @FILE_NAME); RETURN; END; -- verify if directory exists IF @FILE_PATH IS NOT NULL BEGIN DECLARE @TF TABLE (file_exists BIT, file_is_dir BIT, parent_file BIT); INSERT INTO @TF EXEC xp_fileexist @FILE_PATH; IF NOT EXISTS(SELECT * FROM @TF WHERE file_is_dir = 1) BEGIN RAISERROR('The directory %s must exists', 16, 1, @FILE_PATH); RETURN; END; END -- add backslash at the end if not exists IF RIGHT(@FILE_PATH, 1) <> CHAR(92) SET @FILE_PATH = @FILE_PATH + CHAR(92); -- verify the XML syntax of the database list to exclude IF @EXCLUDE_DB IS NOT NULL BEGIN BEGIN TRANSACTION; BEGIN TRY DECLARE @XQL NVARCHAR(max); SET @XQL = 'USE msdb;CREATE XML SCHEMA COLLECTION dbo.XSC_3A586931_C43F_47C1_A419_6E19DB23CEC3 AS N''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="dbs"> <xs:complexType> <xs:sequence> <xs:element type="xs:string" name="db" maxOccurs="unbounded" minOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>'';' EXEC (@XQL); SET @XQL = N'USE msdb;CREATE TABLE dbo.XTB_3A586931_C43F_47C1_A419_6E19DB23CEC3 (data_bases XML (XSC_3A586931_C43F_47C1_A419_6E19DB23CEC3));' EXEC (@XQL) SET @XQL = N'USE msdb;INSERT INTO dbo.XTB_3A586931_C43F_47C1_A419_6E19DB23CEC3 VALUES (''' + CAST(@EXCLUDE_DB AS varchar(max)) + N''');' EXEC (@XQL); ROLLBACK; END TRY BEGIN CATCH IF XACT_STATE() <> 0 ROLLBACK; THROW 55555, 'XML list of databases to exclude is in an uncorrect format. Must be formed like "<dbs><db>database_name1</db><db>database_name2</db></dbs>".', 1; RETURN; END CATCH; END; -- local variables DECLARE @dbid INT, -- the database id @dbname sysname, -- the name of the database @f_name sysname, -- file name for backup @NEWNAME sysname, -- corrected file name @I TINYINT, -- loop indice @SQL NVARCHAR(max), -- SQL code to be dynamically executed @DT DATETIME, -- system datetime @D NCHAR(9), -- backup date encoded as aaaammjjD (like 20181231D) @T NCHAR(9), -- backup time encoded as hhHmmMssS (like 21H38M05S) @ERRORS SMALLINT, -- number of errors @ERRMSG VARCHAR(1024); -- error message -- find the candidate databases CREATE TABLE #dbs (database_id INT PRIMARY KEY, dbname sysname, f_name NVARCHAR(128)); INSERT INTO #dbs (database_id, dbname) SELECT database_id, name FROM sys.databases WHERE state = 0 AND source_database_id IS NULL -- exclude snapshot database AND name NOT IN ('tempdb') -- exclude tempdb AND CASE WHEN @BACKUP_TYPE = 'T' -- transactional backup only if recovery model <> SIMPLE AND recovery_model = 3 THEN 0 ELSE 1 END = 1 AND CASE WHEN @ONLY_USER_DB = 1 -- excluding system database if required AND name IN ('master', 'msdb', 'model') THEN 0 ELSE 1 END = 1 -- excluding database from the XML list AND name NOT IN (SELECT db_name.value('(.)[1]', 'sysname') FROM @EXCLUDE_DB.nodes('/dbs/db') AS TX(db_name)); -- correcting file name to have only letters without accents UPDATE #dbs SET f_name = CAST(dbname collate SQL_Latin1_General_Cp1251_CS_AS AS varchar(128)); -- correcting file name with only letters (A to Z), figures (0 to 9) and underscore (_) DECLARE C1 CURSOR LOCAL FORWARD_ONLY FOR SELECT database_id, f_name FROM #dbs FOR UPDATE OF f_name; OPEN C1; FETCH C1 INTO @dbid, @f_name; WHILE @@FETCH_STATUS = 0 BEGIN SELECT @I = 1, @NEWNAME = N''; WHILE @I <= LEN(@f_name) BEGIN IF SUBSTRING(@f_name, @I, 1) LIKE '[A-Z0-9_]' COLLATE Latin1_General_CI_AS SET @NEWNAME = @NEWNAME + SUBSTRING(@f_name, @I, 1); ELSE SET @NEWNAME = @NEWNAME + N'_'; SET @I = @I + 1; END UPDATE #dbs SET f_name = @NEWNAME WHERE CURRENT OF C1; FETCH C1 INTO @dbid, @f_name; END CLOSE C1; DEALLOCATE C1; SET @ERRORS = 0; -- we use cursor to backup databases one by one, which facilitate the rollback DECLARE C2 CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR SELECT dbname, f_name FROM #dbs; OPEN C2; FETCH C2 INTO @dbname, @f_name; -- loop over the databases WHILE @@FETCH_STATUS = 0 BEGIN -- calculate date and time as strings if needed IF @FILE_DATE = 1 OR @FILE_TIME = 1 SET @DT = CASE @UTC_DATETIME WHEN 0 THEN GETDATE() ELSE GETUTCDATE() END; IF @FILE_DATE = 1 AND @FILE_NAME IS NOT NULL AND @D IS NULL SET @D = CONVERT(CHAR(8), @DT, 112) + 'D'; IF @FILE_TIME = 1 AND @FILE_NAME IS NOT NULL AND @T IS NULL SET @T = FORMAT(CONVERT(TIME, @DT, 108), 'hh\Hmm\Mss\S'); -- compose the backup sql command SET @SQL = N'BACKUP ' + CASE WHEN @BACKUP_TYPE = N'T' THEN N'LOG' ELSE N'DATABASE' END + N' [' + @dbname + N'] TO DISK = ''' + COALESCE(@FILE_PATH, N'') + CASE WHEN @FILE_NAME IS NOT NULL THEN @FILE_NAME ELSE @f_name END + CASE WHEN @FILE_DATE = 1 THEN N'_' + @D ELSE '' END + CASE WHEN @FILE_TIME = 1 THEN N'_' + @T ELSE '' END + CASE WHEN @UTC_DATETIME = 1 THEN N'_UTC' ELSE '' END + N'.' + CASE WHEN @FILE_EXT IS NOT NULL THEN @FILE_EXT ELSE CASE @BACKUP_TYPE WHEN 'F' THEN 'BAK' WHEN 'D' THEN 'DIF' WHEN 'T' THEN 'TRN' ELSE '' END END + N''' WITH ' + CASE WHEN @FILE_FORMAT = 1 THEN N'FORMAT' ELSE N'NOFORMAT' END + CASE WHEN @BACKUP_TYPE = N'D' THEN N', DIFFERENTIAL' ELSE '' END + CASE WHEN @COMPRESSION = 1 THEN N', COMPRESSION' ELSE '' END + N';' -- execute the SQL backup command BEGIN TRY EXEC (@SQL); END TRY BEGIN CATCH -- write a log message if in error SET @ERRMSG = ERROR_MESSAGE(); RAISERROR ('>> BACKUP: %s (SQL command: %s).', 16, 1, @ERRMSG, @SQL) WITH LOG; SET @ERRORS = @ERRORS + 1; FETCH C2 INTO @dbname, @f_name; CONTINUE; END CATCH FETCH C2 INTO @dbname, @f_name; END; CLOSE C2; DEALLOCATE C2; IF @ERRORS >0 THROW 55555, 'Almost one backup exception has been raised. Check SQL logs to find entries beginning with ">> BACKUP:".', 1; GO
La forme XML du document pour exclure les bases doit être basé qui la modèle suivant :
<dbs> <db><em>database_name1</em></db> <db><em>database_name2</em></db> </dbs>
Fonctionne à partir de la version 2012 de SQL Server et nécessite un privilège ayant le rôle de sysadmin ou équivalent.
En cas d’erreur, les exécutions ratées sont journalisée dans le journal d’événement de SQL Server.
CONSEIL : créez la dans la base msdb et dans un schéma spécifique que vous allez créer pour l’occasion. Pour ma part j’utilise un schema de nom _MAINTENANCE dans msdb pour tous ces outils (notez le blanc souligné devant le nom… Hé oui, c’est permis !
Exemple d’utilisation :
EXEC dbo.P_BACKUP_ALL_DATABASE @BACKUP_TYPE = 'T', @FILE_PATH = NULL, @FILE_EXT = NULL, @FILE_NAME = 'mes_bases', @FILE_DATE = 1, @FILE_TIME = 1, @FILE_FORMAT = 1, @UTC_DATETIME = 1, @ONLY_USER_DB = 1, @EXCLUDE_DB = N'<dbs><db>ReportServer$SQL2016FBIN2</db><db>ReportServer$SQL2016FBIN2TempDB</db></dbs>', @COMPRESSION = 1
Ceci effectue les sauvegardes transactionnelle compresséesde toutes les bases candidates à l’exception des bases systèmes, des base en mode de récupération simple et des bases « ReportServer.. » listé dans le XML d’exclusion et envoie le tout dans un seul fichier de nom « mes_bases_20180529D_14H02M58S_UTC.TRN » si la commande a été lancé le 29/5/2018 à 14h02 et 58s (en temps universel) et place le tout dans le répertoire par défaut des sauvegardes.
Le lien de téléchargement du code
Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
* Le site sur les SGBD relationnels et le SQL : https://sqlpro.developpez.com *
* le blog SQL, SQL Server, SGBDR... sur : https://blog.developpez.com/sqlpro/ *
* Expert Microsoft SQL Server, MVP (Most valuable Professional) depuis 14 ans *
* Entreprise SQL SPOT : modélisation, conseil, audit, optimisation, formation *
* * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *