2010-10-29 105 views
18

我有存儲在一個表中的MS SQL Server 2005中有沒有人有SQL代碼,需要查詢作爲輸入(可以說查詢保證返回VARBINARY的單個列一些varbinary數據)並將這些字節輸出到磁盤(每行一個文件?)我確信這個問題以前已經有過一千次的問題,但谷歌搜索主要提供了.net解決方案。我想要一個SQL解決方案。腳本varbinary數據保存到磁盤

回答

27

BCP的做法並不爲我工作。它寫入磁盤的字節不能被反序列化回我存儲的.net對象。這意味着磁盤上的字節與存儲的字節不同。也許BCP正在寫某種標題。我不確定。

我發現下面的代碼here在文章底部。它很棒!雖然它是用於存儲BMP圖像的,但它適用於任何varbinary。

DECLARE @SQLIMG VARCHAR(MAX), 
    @IMG_PATH VARBINARY(MAX), 
    @TIMESTAMP VARCHAR(MAX), 
    @ObjectToken INT 

DECLARE IMGPATH CURSOR FAST_FORWARD FOR 
     SELECT csl_CompanyLogo from mlm_CSCompanySettingsLocalizations 

OPEN IMGPATH 

FETCH NEXT FROM IMGPATH INTO @IMG_PATH 

WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @TIMESTAMP = 'd:\' + replace(replace(replace(replace(convert(varchar,getdate(),121),'-',''),':',''),'.',''),' ','') + '.bmp' 

     PRINT @TIMESTAMP 
     PRINT @SQLIMG 

     EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT 
     EXEC sp_OASetProperty @ObjectToken, 'Type', 1 
     EXEC sp_OAMethod @ObjectToken, 'Open' 
     EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH 
     EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @TIMESTAMP, 2 
     EXEC sp_OAMethod @ObjectToken, 'Close' 
     EXEC sp_OADestroy @ObjectToken 

     FETCH NEXT FROM IMGPATH INTO @IMG_PATH 
    END 

CLOSE IMGPATH 
DEALLOCATE IMGPATH 
+2

運行這個可能需要啓用OLE自動化程序https://msdn.microsoft.com/en-us/library/ms191188.aspx。 – 2016-05-05 02:56:31

11

您可以使用BCP,不是T-SQL,但效果很好。

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T 
+1

嗨達斯汀 - 我能夠使用命令輸出文件,但我不認爲它的工作正常。數據是一個序列化的.net對象。我知道數據是正確存儲的,因爲我的進程使用.net的數據進行操作。但是,當我嘗試反序列化時,我得到一個錯誤,這意味着字節寫入不正確。思考?如果命令輸出單個varbinary(max)值,是寫入磁盤的實際字節還是包含頭文件等? – SFun28 2010-10-30 15:12:54

+1

使用-N選項似乎可以正常工作 – 2013-12-19 03:26:17

+3

提示時使用以下選項: - 輸入字段XXX [varbinary(max)]的文件存儲類型: - 輸入字段XXX的前綴長度[8 ]:0 - 輸入領域XXX [0]的長度: - 輸入字段終止[無]: - 你想保存在一個文件格式的信息? [Y/n] n breez 2015-10-15 10:33:08

0

SQL旨在與數據庫對象一起工作,因此從其角度來看,其他任何東西都不存在。當然,像xp_cmdshell這樣的擴展程序允許您與操作系統進行交互,但它們是專有擴展,而不是T-SQL的一部分。

也許最接近將使用二進制類型的SQL Server 2008中的,允許直接存儲一些列的文件的文件夾中,而不是使用數據庫FILESTREAM屬性:

FILESTREAM overview

注意:的FILESTREAM存儲裝置進行以提高性能保持大文件從數據庫中,而不是允許直接訪問文件(即T-SQL仍然沒有一個文件系統)的概念設計。我認爲,從SQL直接訪問文件系統將會破壞數據庫的一些目的(主要是以結構化方式存儲數據)。

因此,我建議以下達斯汀的建議,使用像BCP或任何其他數據自卸車的工具。

3

我知道這是舊的文章,但我想通了,爲什麼下面不工作,如何解決它:

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.JPG" -T -N 

原因是BCP把前綴長度在一開始文件。它是4字節或8字節,取決於FileContent列的數據類型(文本,ntext,圖像:4 varchar(max),varbinary(max):8請參考https://msdn.microsoft.com/en-us/library/ms190779.aspx

使用二進制編輯器一個在Visual Studio中,用於刪除前綴字節,並且所有內容都完美運行。 :-)

1

如果您linqpad,這個工程:

void Main() 
{ 
    var context = this; 
    var query = 
     from ci in context.Images 
     where ci.ImageId == 10 
     select ci.Image 
    ; 
    var result = query.Single(); 
    var bytes = Convert.FromBase64String(result); 
    File.WriteAllBytes(@"c:\image.bmp", bytes); 
} 
+0

Pitch Perfect .. – irfandar 2016-03-03 11:27:18

+2

This works ...?真的,所以'var context = this'會自動搜索你的sql server實例,將會登錄,會找到正確的數據庫,其中有一個圖表存在的方案...從來不知道LinqPad是這個聰明的! – 2016-04-12 14:23:21

+0

你有沒有用過它?它並非如此。我猜想,我只是在想象它。 – JohnOpincar 2016-04-14 15:20:09

2

只是一個替代品。您可以使用免費軟件Toad for sql server並直接從編輯器保存。

enter image description here

3

我加入這個建立在JohnOpincar的回答,讓別人誰想要使用LinqPad可以得到一個有效的解決方案更快。

/* 
This LinqPad script saves data stored in a VARBINARY field to the specified folder. 
1. Connect to SQL server and select the correct database in the connection dropdown (top right) 
2. Change the Language to C# Program 
3. Change "Attachments" to the name of your table that holds the VARBINARY data 
4. Change "AttachmentBuffer" to the name of the field that holds the data 
5. Change "Id" to the unique identifier field name 
6. Change "1090" to the identity of the record you want to save 
7. Change the path to where you want to save the file. Make sure you choose the right extension. 

Notes: Windows 10 may give you "Access Denied" error when trying to save directly to C:\. Rather save to a subfolder. 
*/ 

void Main() 
{ 
    var context = this; 
    var query = 
     from ci in context.Attachments 
     where ci.Id == 1090 
     select ci.AttachmentBuffer 
    ; 
    byte[] result = query.Single().ToArray(); 
    File.WriteAllBytes(@"c:\DEV\dumpfile.xlsx", result); 
    Console.WriteLine("Done"); 
}