2012-08-30 9 views
7

Sto tentando di esportare un numero piuttosto elevato di file di immagine, memorizzati internamente in un database SQL come dati binari.Esportazione di dati di file binari (immagini) da SQL tramite una stored procedure

Essendo abbastanza nuovo per scrivere stored procedure in SQL, mi sono imbattuto in un paio di guide molto utili su come questo può essere archiviato, ma mi sembra che manchi qualcosa.

Sto eseguendo SQL Server 2008 R2 localmente e sto provando a scrivere i file in una cartella sul mio C: \ drive.

qui è la parte buisness di ciò che ho finora:

BEGIN 
DECLARE @cmd VARCHAR(8000) 
DECLARE @result int 

DECLARE curExportBinaryDocs CURSOR FAST_FORWARD FOR 
SELECT 'BCP "SELECT Photograph_Data FROM [ALBSCH Trial].[dbo].[Photograph] WHERE Photograph_ID = ' 
    + CAST(Photograph_ID AS VARCHAR(500)) + '" queryout "' + @OutputFilePath 
    + CAST(Photograph_ID AS VARCHAR(500)) + '.jpg"' + ' -n -T' 
FROM dbo.Photograph 

OPEN curExportBinaryDocs 
FETCH NEXT FROM curExportBinaryDocs INTO @cmd 
WHILE @@FETCH_STATUS = 0 
    BEGIN 
    --PRINT @cmd 
    EXEC @result = xp_cmdshell @cmd   
    FETCH NEXT FROM curExportBinaryDocs INTO @cmd 
    END 
CLOSE curExportBinaryDocs 
DEALLOCATE curExportBinaryDocs 
END 

'@result' viene sempre impostato a '1' (fallito) dopo la chiamata xp_cmdshell. Tutti i nomi/campi della tabella sono corretti, quindi sospetto che ci sia qualcosa di sbagliato nella mia chiamata BCP, ma non sono sicuro di cosa provare dopo.

Qualsiasi aiuto o consiglio sarebbe molto gradito.

+0

Come si esegue SQL? L'SQL viene eseguito con le credenziali dell'utente ... Quell'utente ha i diritti per creare file nella cartella di output? –

+0

Accedo al server SQL utilizzando il mio solito nome utente Windows e l'autenticazione di Windows. Sono riuscito a far funzionare una soluzione utilizzando il metodo descritto qui: http://stackoverflow.com/questions/1366544/how-to-export-image-field-to-file ma se possibile mi piacerebbe arrivare a la parte inferiore del problema che sto avendo con il mio metodo originale, solo per la pace della mente! – ChrisMurray

+0

Credo che quello che stai facendo sia un po 'sbagliato. Conosci il "Database di abilitazione del flusso di file" di SQL Server. Consente di archiviare BLOB sul disco rigido mentre i BLOB sono ancora gestiti dal server SQL. Dopo aver selezionato questo BLOB sull'unità, l'applicazione deve solo eseguire una query sul database e ottenere l'oggetto. Inoltre, usare il cursore non è una buona cosa (è lento). – gotqn

risposta

5

Beh, prima di tutto .. (e dispiace;)) Don "utilizzare i cursori T .. e dispiaciuto per i tappi ...

uno dei più cose baddest circa i cursori sono che essi può bloccare il vostro tavolo. quello che faccio sempre per questi scopi (e che è abbastanza veloce), io uso un ciclo for .. Ti piace questa

declare @totrow int 
     , @currow int 
     , @result int 
     , @nsql nvarchar(max) 

declare @sqlStatements table (
    Id int identity(1, 1) 
, SqlStatement varchar(max) 
) 
insert 
into @sqlStatements 
select 'QUERY PART' 
from table 

set @totrow = @@rowcount 
set @currow = 1 
while @totrow > 0 and @currow <= @totrow 
begin 
    select @nsql = SqlStatement 
    from @SqlStatements 
    where Id = @currow 

    exec @result = xp_cmdshell @nsql 

    set @currow = @currow + 1 
end 

per la prossima parte, fa il processo di SQL Server ha abbastanza il permesso di scrivi sul c: drive? Inoltre, guarda nel riquadro dei messaggi quando esegui il codice, forse puoi trovare qualcosa lì?

Cosa puoi fare, prova ad eseguirlo manualmente. Basta ottenere una dichiarazione BCP ed eseguirla con xp_cmdshell. Fornisce errori?

+0

Grazie Mark Mi ero trasferito da questo dopo aver trovato una soluzione diversa al lavoro, ma visto i tuoi commenti sono andato a dare un'altra occhiata. Dopo aver modificato il mio codice per evitare di usare il cursore e poi lottare con le permissioni di BCP e le stranezze delle virgolette, ora funziona correttamente! Molte grazie. Voterò la tua risposta, ma non ho ancora un rappresentante abbastanza alto :) – ChrisMurray

+0

Piacere di sentirlo aiutato :) –

+0

@MarkKremers mentre hai ragione i cursori sono cattivi, troverai che i loop sono implementati tramite cursori e che i cursori forniscono più controllo sulle prestazioni, così mentre i loop hanno prestazioni migliori dei cursori corretti: http://sqlblog.com/blogs/aaron_bertrand/archive/2012/01/26/the-fallacy-that-a-while-loop-isn-ta- cursor.aspx – ConstantineK

6

Ecco la mia procedura di lavoro finale e il file di formato. Non sono riuscito a trovare i dettagli più precisi dei comandi BCP , le impostazioni di permissione e il layout dei file in un unico posto, quindi forse questo sarà utile a qualcuno.

CREATE PROCEDURE [dbo].[ImgExport] 
    @OutputFilePath VARCHAR(500) = 'C:\SQLTest\ ' 
AS 
BEGIN 
    DECLARE @totrow int 
    DECLARE @currow int 
    DECLARE @result int 
    DECLARE @nsql nvarchar(4000) 
    DECLARE @sqlStatements table (ID int IDENTITY(1, 1), SqlStatement varchar(max)) 

    INSERT 
    INTO @sqlStatements 
    SELECT 'BCP "SELECT Photograph_Data FROM [ALBSCH_Trial].[dbo].[Photograph] WHERE Photograph_ID = ''' 
    + CAST(Photograph_ID AS VARCHAR(500)) + '''" queryout ' + @OutputFilePath 
    + CAST(Photograph_ID AS VARCHAR(500)) + '.jpg -S localhost\SQLEXPRESS2008 -T -f C:\SQLTest\Images.fmt' 
    FROM dbo.Photograph 

    SET @totrow = @@ROWCOUNT 
    SET @currow = 1 
    WHILE @totrow > 0 and @currow <= @totrow 
    BEGIN 
     SELECT @nsql = SqlStatement 
     FROM @sqlStatements 
     WHERE ID = @currow 
     EXEC @result = xp_cmdshell @nsql 
     SET @currow = @currow + 1 
    END 
END  

Formato file:

9.0 
1 
1  SQLBINARY  0  0  "\t"  1  Photograph_Data         "" 

Mi auguro che aiuta qualcuno.

+1

Salve, @ChrisMurray, poiché il contenuto di questa colonna è dati binari/non elaborati, è possibile evitare il file di formattazione fornendo il flag '-N' alla riga di comando BCP, ad esempio:' BCP "SELECT Dati FROM [ Photograph] WHERE ID = 123; " queryout "123.jpg" -S localhost \ SQLEXPRESS2008 -T -N' –

+0

Non è stato possibile produrre Tif che è possibile aprire utilizzando -N anziché il file di formattazione. Apparentemente perché stava aggiungendo alcuni byte di intestazione di qualche tipo. Se si omettono tutte le opzioni di formattazione nella prima chiamata BCP, verranno richiesti i parametri di formattazione. Ho accettato i valori di default tranne i byte di intestazione che ho impostato a zero. Quindi mi ha richiesto di salvare il file che ho poi fatto riferimento nelle altre mie richieste BCP usando il flag -f. – user2027080

Problemi correlati