Extraire un champ de RESTORE HEADERONLY

12

J'essaie d'utiliser ' RESTORE HEADERONLY ' pour obtenir la date à laquelle la sauvegarde que je suis sur le point de restaurer a été effectuée.

La commande:

RESTORE HEADERONLY FROM DISK = '<path to .bak file>'

fonctionne bien dans l'Analyseur de requêtes et donne un jeu de résultats avec quelque chose comme 50 colonnes.

Le problème consiste en fait à y accéder à partir du code.

Je peux obtenir ceci dans une table temporaire en déclarant chacune des colonnes 50: ish, en y insérant avec execet en obtenant la valeur que je veux à partir de là.

Le problème est que je veux vraiment éviter d'avoir à déclarer l'ensemble des résultats comme une table temporaire car cela semble être une solution très fragile s'ils y ajoutent des colonnes dans les futures versions.

Existe-t-il un moyen de récupérer une seule colonne de cet ensemble de résultats sans déclarer toutes les colonnes?

alun
la source

Réponses:

12

Cela fonctionne pour moi.

SELECT BackupStartDate 
FROM OPENROWSET('SQLNCLI',
                'Server=MARTINPC\MSSQL2008;Trusted_Connection=yes;',
'SET NOCOUNT ON;SET FMTONLY OFF;EXEC(''
RESTORE HEADERONLY 
FROM DISK = ''''C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQL2008\MSSQL\Backup\DB1.bak''''
'')'
) 

L' option de requêtes distribuées ad hoc doit être activée. Ou si vous ne voulez pas faire cela, vous pouvez configurer un serveur lié en boucle et l'utiliser à la place.

EXEC sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                        @provider = 'SQLOLEDB', @datasrc = @@servername

SELECT BackupStartDate 
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC(''
               RESTORE HEADERONLY 
               FROM DISK = ''''C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQL2008\MSSQL\Backup\DB1.bak''''
'')')
Martin Smith
la source
Intelligent, et merci pour le partage, mais pour mémoire, je pense que c'est aussi fragile / complexe que la grande liste de colonnes à la fin. Dommage qu'il n'y ait pas de solution élégante.
Tim Abell du
@TimAbell - Oui, je ne pense pas que j'utiliserais cela en pratique, sauf peut-être pour obtenir la définition de la table en premier lieu.
Martin Smith
1
Je n'ai pas pu faire fonctionner l'une ou l'autre des requêtes. Quelqu'un d'autre reçoit-il le message d'erreur "Les métadonnées n'ont pas pu être déterminées car l'instruction RESTORE HEADERONLY ... ne prend pas en charge la découverte des métadonnées"? Je crois que le sp_describe_first_result_setsystème sp est le coupable derrière. J'ai également soulevé cette question en tant que ticket séparé ici
Stackoverflowuser
@Stackoverflowuser - on dirait que j'ai initialement testé cela sur une instance de 2008 (de MARTINPC\MSSQL2008), donc peut-être que quelque chose a changé dans les versions ultérieures, ce qui signifie que cela ne fonctionne plus.
Martin Smith
1
@Stackoverflowuser, l'exemple ci-dessus fonctionne lorsque le serveur @@ version <2012. À partir de 2012, au lieu d'exécuter cette requête, vous pouvez voir dans le profileur celui-ci: exec [sys] .sp_describe_first_result_set N'SET FMTONLY OFF; EXEC ('' RESTORE HEADERONLY FROM DISK = '' '' C: \ Program Files \ Microsoft SQL Server \ MSSQL10.MSSQL2008 \ MSSQL \ Backup \ DB1.bak '' '' '') '', NULL, 1
sepupic
7

Il s'agit d'un sp indépendant de la version que j'ai écrit pour obtenir la date de sauvegarde à partir d'un fichier.

Il est testé pour SQL 2008R2, 2012 et 2014.

IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'spGetBackupDateFromFile')
    EXEC ('CREATE PROC dbo.spGetBackupDateFromFile AS SELECT ''stub version, to be replaced''')
GO
/*----------------------------------------------------------------------
                    spGetBackupDateFromFile
------------------------------------------------------------------------
Versie      : 1.0
Autheur     : Theo Ekelmans 
Datum       : 2016-03-31
Change      : Initial release 
------------------------------------------------------------------------*/
alter procedure dbo.spGetBackupDateFromFile(@BackupFile as varchar(1000), @DT as datetime output) as 

declare @BackupDT datetime
declare @sql varchar(8000)
declare @ProductVersion NVARCHAR(128)
declare @ProductVersionNumber TINYINT

SET @ProductVersion = CONVERT(NVARCHAR(128),SERVERPROPERTY('ProductVersion'))
SET @ProductVersionNumber = SUBSTRING(@ProductVersion, 1, (CHARINDEX('.', @ProductVersion) - 1))

if object_id('dbo.tblBackupHeader') is not null drop table dbo.tblBackupHeader

set @sql = ''

-- THIS IS GENERIC FOR SQL SERVER 2008R2, 2012 and 2014
if @ProductVersionNumber in(10, 11, 12)
set @sql = @sql +'
create table dbo.tblBackupHeader
( 
    BackupName varchar(256),
    BackupDescription varchar(256),
    BackupType varchar(256),        
    ExpirationDate varchar(256),
    Compressed varchar(256),
    Position varchar(256),
    DeviceType varchar(256),        
    UserName varchar(256),
    ServerName varchar(256),
    DatabaseName varchar(256),
    DatabaseVersion varchar(256),        
    DatabaseCreationDate varchar(256),
    BackupSize varchar(256),
    FirstLSN varchar(256),
    LastLSN varchar(256),        
    CheckpointLSN varchar(256),
    DatabaseBackupLSN varchar(256),
    BackupStartDate varchar(256),
    BackupFinishDate varchar(256),        
    SortOrder varchar(256),
    CodePage varchar(256),
    UnicodeLocaleId varchar(256),
    UnicodeComparisonStyle varchar(256),        
    CompatibilityLevel varchar(256),
    SoftwareVendorId varchar(256),
    SoftwareVersionMajor varchar(256),        
    SoftwareVersionMinor varchar(256),
    SoftwareVersionBuild varchar(256),
    MachineName varchar(256),
    Flags varchar(256),        
    BindingID varchar(256),
    RecoveryForkID varchar(256),
    Collation varchar(256),
    FamilyGUID varchar(256),        
    HasBulkLoggedData varchar(256),
    IsSnapshot varchar(256),
    IsReadOnly varchar(256),
    IsSingleUser varchar(256),        
    HasBackupChecksums varchar(256),
    IsDamaged varchar(256),
    BeginsLogChain varchar(256),
    HasIncompleteMetaData varchar(256),        
    IsForceOffline varchar(256),
    IsCopyOnly varchar(256),
    FirstRecoveryForkID varchar(256),
    ForkPointLSN varchar(256),        
    RecoveryModel varchar(256),
    DifferentialBaseLSN varchar(256),
    DifferentialBaseGUID varchar(256),        
    BackupTypeDescription varchar(256),
    BackupSetGUID varchar(256),
    CompressedBackupSize varchar(256),'

-- THIS IS SPECIFIC TO SQL SERVER 2012
if @ProductVersionNumber in(11)
set @sql = @sql +'
    Containment varchar(256),'


-- THIS IS SPECIFIC TO SQL SERVER 2014
if @ProductVersionNumber in(12)
set @sql = @sql +'
    Containment tinyint, 
    KeyAlgorithm nvarchar(32), 
    EncryptorThumbprint varbinary(20), 
    EncryptorType nvarchar(32),'


--All versions (This field added to retain order by)
set @sql = @sql +'
    Seq int NOT NULL identity(1,1)
); 
'
exec (@sql)


set @sql = 'restore headeronly from disk = '''+ @BackupFile +'''' 

insert into dbo.tblBackupHeader 
exec(@sql)

select @DT = BackupStartDate from dbo.tblBackupHeader 

if object_id('dbo.tblBackupHeader') is not null drop table dbo.tblBackupHeader
user3742089
la source
1
Selon stackoverflow.com/a/31318785/489865 et support.microsoft.com/en-us/kb/3058865 , le KeyAlgorithm / EncryptorThumbprint / EncryptorType que vous avez ajouté pour "SQL SERVER 2014" n'apparaît en fait que dans SP1. Je crois que la version de construction pour cela est 12.0.4100.1, donc le code devrait regarder tous les champs SERVERPROPERTY('ProductVersion')pour répondre correctement à cela.
JonBrave
7

Étant donné que vous avez uniquement demandé à accéder aux données à partir du «code» sans spécifier de détails sur le type de code, je présente la solution PowerShell :

Invoke-SQLcmd -Query "RESTORE HEADERONLY FROM DISK = 'R:\SQLFiles\MSSQL.MSSQLSERVER.Backup\Backup.bak'" | Select-Object MachineName,DatabaseName,HasBackupChecksums,BackupStartDate,BackupFinishDate
Christoph Wegener
la source
1
C'est encore mieux, car nous pouvons faire quelque chose comme `ls | % {$ _. nom complet} | % {invoke-sqlcmd -Query "RESTORE HEADERONLY FROM DISK = '$ _'"} | format-table `
Luiz Felipe
6

La manière ancienne, pour référence:

declare @backupFile varchar(max) = 'C:\backupfile.bak';
declare @dbName varchar(256);

-- THIS IS SPECIFIC TO SQL SERVER 2012
--
declare @headers table 
( 
    BackupName varchar(256),
    BackupDescription varchar(256),
    BackupType varchar(256),        
    ExpirationDate varchar(256),
    Compressed varchar(256),
    Position varchar(256),
    DeviceType varchar(256),        
    UserName varchar(256),
    ServerName varchar(256),
    DatabaseName varchar(256),
    DatabaseVersion varchar(256),        
    DatabaseCreationDate varchar(256),
    BackupSize varchar(256),
    FirstLSN varchar(256),
    LastLSN varchar(256),        
    CheckpointLSN varchar(256),
    DatabaseBackupLSN varchar(256),
    BackupStartDate varchar(256),
    BackupFinishDate varchar(256),        
    SortOrder varchar(256),
    CodePage varchar(256),
    UnicodeLocaleId varchar(256),
    UnicodeComparisonStyle varchar(256),        
    CompatibilityLevel varchar(256),
    SoftwareVendorId varchar(256),
    SoftwareVersionMajor varchar(256),        
    SoftwareVersionMinor varchar(256),
    SoftwareVersionBuild varchar(256),
    MachineName varchar(256),
    Flags varchar(256),        
    BindingID varchar(256),
    RecoveryForkID varchar(256),
    Collation varchar(256),
    FamilyGUID varchar(256),        
    HasBulkLoggedData varchar(256),
    IsSnapshot varchar(256),
    IsReadOnly varchar(256),
    IsSingleUser varchar(256),        
    HasBackupChecksums varchar(256),
    IsDamaged varchar(256),
    BeginsLogChain varchar(256),
    HasIncompleteMetaData varchar(256),        
    IsForceOffline varchar(256),
    IsCopyOnly varchar(256),
    FirstRecoveryForkID varchar(256),
    ForkPointLSN varchar(256),        
    RecoveryModel varchar(256),
    DifferentialBaseLSN varchar(256),
    DifferentialBaseGUID varchar(256),        
    BackupTypeDescription varchar(256),
    BackupSetGUID varchar(256),
    CompressedBackupSize varchar(256),        
    Containment varchar(256),
    --
    -- This field added to retain order by
    --
    Seq int NOT NULL identity(1,1)
); 

insert into @headers exec('restore headeronly from disk = '''+ @backupFile +'''');
select @dbName = DatabaseName from @headers;
select @dbName;
ryscl
la source
1
Pour que cela fonctionne dans SQL2014, vous aurez besoin d'avoir ces champs supplémentaires à la fin du tableau:, Containment tinyint, KeyAlgorithm nvarchar (32), EncryptorThumbprint varbinary (20), EncryptorType nvarchar (32)
Mike
Il y a aussi cette réponse , qui n'utilise pas varchar pour tout, et inclut les colonnes supplémentaires pour SQL Server 2014.
Baodad
Notez que ces colonnes supplémentaires ont en fait été ajoutées dans SQL 2014 SP1 . Je crois que la version de construction pour cela est 12.0.4100.1.
JonBrave