44

我有一些 varbinary 数据存储在 MS Sql Server 2005 的表中。有没有人有将查询作为输入的 SQL 代码(假设查询保证返回单列 varbinary)并将字节输出到磁盘(一个文件每行?)我敢肯定这已经被问过一千次了,但谷歌搜索主要是.net解决方案。我想要一个 SQL 解决方案。

4

8 回答 8

48

BCP 方法对我不起作用。它写入磁盘的字节不能反序列化回我存储的 .net 对象。这意味着磁盘上的字节不等于存储的内容。也许 BCP 正在编写某种标题。我不知道。

我在文章底部找到了以下代码。效果很好!虽然它适用于存储的 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
于 2010-11-03T14:22:43.743 回答
26

我在JohnOpincar's answer 的基础上添加了这个,以便其他想要使用 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");
}
于 2016-11-10T05:53:48.737 回答
13

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

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T
于 2010-10-29T21:39:52.117 回答
7

我知道这是一篇旧帖子,但我知道为什么以下内容不起作用以及如何解决它:

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

原因是 bcp 将 Prefix Length 放在文件的最开头。它是 4 字节还是 8 字节,取决于 FileContent 列的数据类型(text、ntext、image:4 varchar(max)、varbinary(max):8 请参阅https://msdn.microsoft.com/en-us /图书馆/ms190779.aspx

使用二进制编辑器(如 Visual Studio 中的编辑器)删除前缀字节,一切都运行良好。:-)

于 2015-12-21T22:56:22.860 回答
6

如果您有 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);
}
于 2016-01-28T21:37:47.143 回答
3

使用 Powershell

function SQLExecuteScalar([string]$pServer, [string]$pDatabase, [string]$pQuery)
{
    # Connection
    $pSQLConnection = New-Object System.Data.SqlClient.SqlConnection
    $pSQLConnection.ConnectionString = "Data Source=$($pServer);Initial Catalog=$($pDatabase);Integrated Security=SSPI;Application Name=FileExtractor.Powershell"
    $pSQLConnection.Open()

    # Command
    [System.Data.SqlClient.SqlCommand]$cmd = New-Object System.Data.SqlClient.SqlCommand($pQuery, $pSQLConnection)

    # Execute and Get scalar value
    [byte[]]$return = $cmd.ExecuteScalar()
    
    # Close Connection
    $pSQLConnection.Close()

    # Result to pipe
    return $return
}

[string]$Server = "MyServer"
[string]$DataBase = "MyDb"
[string]$Query = "select BlobValue from dbo.MyTable"
[string]$FileName = "C:\Temp\BlobValue.bin"

SQLExecuteScalar -pServer $Server -pDatabase $DataBase -pQuery $Query | Set-Content $FileName -Encoding Byte
于 2020-11-12T09:35:19.730 回答
1

只是一种选择。您可以使用免费软件 Toad for SQL server 并直接从编辑器中保存。

您可以访问他们的网站https://www.toadworld.com并在那里获取免费软件或完整版的 30 天试用版。它在下载并选择 Toad for SQL server。

在此处输入图像描述

您在 Toad 中对包含您要保存的图像的行执行常规选择语句。当您看到结果时,您可以单击字节图像列,如果这是 PDF 文档,您可以在右侧看到 PDF 选项卡,或者在左侧看到图像选项卡。单击选项卡时,您可以在底部看到保存徽标以保存图像或文件。

于 2016-10-13T10:51:29.917 回答
-1

SQL 旨在处理数据库对象,因此从它的角度来看,其他任何东西都不存在。当然,有类似的扩展过程xp_cmdshell允许您与操作系统交互,但它们是专有扩展,而不是 T-SQL 的一部分。

也许最接近的方法是对 SQL Server 2008 的二进制类型使用 FILESTREAM 属性,它允许将某些列直接作为文件存储在文件夹中,而不是使用数据库:

文件流概述

请注意,FILESTREAM 存储旨在维护数据库外的大文件以提高性能,而不是允许直接访问文件(即 T-SQL 仍然没有文件系统的概念)。我认为,从 SQL 直接访问文件系统将破坏数据库的某些目的(主要是以结构化方式存储数据)。

因此,我建议遵循 Dustin 的建议,使用 BCP 或任何其他数据转储器之类的工具。

于 2010-10-31T13:24:42.500 回答