Extraindo um campo de RESTORE HEADERONLY

12

Estou tentando usar ' RESTORE HEADERONLY ' para obter a data em que o backup que estou prestes a restaurar foi feito.

O comando:

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

funciona bem no Query Analyzer e fornece um conjunto de resultados com algo como 50 colunas.

O problema é realmente acessar isso a partir do código.

Eu posso colocar isso em uma tabela temporária declarando cada uma das colunas 50: ish, inserindo nela exece obtendo o valor que eu quero a partir daí.

O problema é que eu realmente quero evitar ter que declarar todo o conjunto de resultados como uma tabela temporária, pois parece uma solução muito frágil se eles adicionarem colunas a ele em versões futuras.

Existe alguma maneira de obter uma única coluna desse conjunto de resultados sem declarar todas as colunas?

alun
fonte

Respostas:

12

Isso funciona para mim.

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''''
'')'
) 

A opção de consultas distribuídas ad hoc precisa estar ativada. Ou, se você não quiser fazer isso, poderá configurar um servidor vinculado a loopback e usá-lo.

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
fonte
Inteligente e obrigado por compartilhar, mas apenas pelo registro, acho que isso é tão frágil / complexo quanto a grande lista de colunas no final. Pena que não há uma solução elegante.
Tim Abell 15/10
@ TimAbell - Sim, acho que não usaria isso na prática, exceto talvez para obter a definição da tabela em primeiro lugar.
Martin Smith
1
Não consegui fazer nenhuma consulta funcionar. Alguém mais recebeu a mensagem de erro "Não foi possível determinar os metadados porque a instrução RESTORE HEADERONLY ... não suporta a descoberta de metadados"? Acredito que o sp_describe_first_result_setsistema sp é o culpado por trás. Eu também levantou esta questão como um bilhete separado aqui
Stackoverflowuser
@Stackoverflowuser - parece que eu originalmente testei isso em uma instância de 2008 (de MARTINPC\MSSQL2008), então talvez algo tenha mudado nas versões posteriores, o que significa que isso não funciona mais.
Martin Smith
1
@Stackoverflowuser, o exemplo acima funciona quando o servidor @@ versão <2012. A partir de 2012, em vez de executar esta consulta, você pode ver no Profiler este: exec [sys] .sp_describe_first_result_set N'SET FMTONLY OFF; EXEC ('' RESTORE HEADERONLY FROM DISK = '' '' C: \ Arquivos de Programas \ Microsoft SQL Server \ MSSQL10.MSSQL2008 \ MSSQL \ Backup \ DB1.bak '' '' '' ')', NULL, 1
sepupic
7

Esta é uma versão independente do sp que escrevi para obter a data de backup de um arquivo.

Foi testado para SQL 2008R2, 2012 e 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
fonte
1
Conforme stackoverflow.com/a/31318785/489865 e support.microsoft.com/en-us/kb/3058865 , o KeyAlgorithm / EncryptorThumbprint / EncryptorType que você adicionou para "SQL SERVER 2014" realmente apareceu apenas no SP1. Eu acredito que a versão Build para isso é 12.0.4100.1, então o código deve examinar todos os campos SERVERPROPERTY('ProductVersion')para atender corretamente a isso.
JonBrave
7

Como você só perguntou sobre o acesso aos dados do 'código' sem especificar detalhes de que tipo de código, apresento a solução do PowerShell :

Invoke-SQLcmd -Query "RESTORE HEADERONLY FROM DISK = 'R:\SQLFiles\MSSQL.MSSQLSERVER.Backup\Backup.bak'" | Select-Object MachineName,DatabaseName,HasBackupChecksums,BackupStartDate,BackupFinishDate
Christoph Wegener
fonte
1
Isso é ainda melhor, pois podemos fazer algo como `ls | % {$ _. nome completo} | % {invoke-sqlcmd -Query "RESTAURAR HEADERONLY FROM DISK = '$ _'"} | format-table `
Luiz Felipe
6

À moda antiga, para referência:

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
fonte
1
Para que isso funcione no SQL2014, você precisará dos seguintes campos adicionais no final da tabela:, Minuto de contenção, KeyAlgorithm nvarchar (32), EncryptorThumbprint varbinary (20), EncryptorType nvarchar (32)
Mike
Há também essa resposta , que não usa varchar para tudo, e inclui as colunas extras para SQL Server 2014.
Baodad
Observe que essas colunas extras foram realmente adicionadas no SQL 2014 SP1 . Eu acredito que a versão Build para isso é 12.0.4100.1.
JonBrave