Sql 将varbinary数据保存到磁盘的脚本

Sql 将varbinary数据保存到磁盘的脚本,sql,sql-server,sql-server-2005,varbinary,Sql,Sql Server,Sql Server 2005,Varbinary,我有一些varbinary数据存储在MSSQLServer2005的一个表中。有没有人有SQL代码将一个查询作为输入(假设该查询保证返回一列varbinary)并将字节输出到磁盘(每行一个文件?)我相信这已经被问过一千次了,但谷歌提出的解决方案大多是.net。我想要一个SQL解决方案。您可以使用BCP,而不是T-SQL,但效果很好 BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T SQL设计用于

我有一些varbinary数据存储在MSSQLServer2005的一个表中。有没有人有SQL代码将一个查询作为输入(假设该查询保证返回一列varbinary)并将字节输出到磁盘(每行一个文件?)我相信这已经被问过一千次了,但谷歌提出的解决方案大多是.net。我想要一个SQL解决方案。

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

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

SQL设计用于处理数据库对象,因此从它的角度来看,其他任何东西都不存在。当然,有一些扩展过程,如
xp\u cmdshell
,允许您与操作系统交互,但它们是专有的扩展,不是T-SQL的一部分

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

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


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

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

我知道这是一篇老文章,但我明白了以下内容不起作用的原因以及如何修复它:

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.JPG" -T -N
原因是bcp将前缀长度放在文件的最开头。它是4字节还是8字节,取决于FileContent列的数据类型(text、ntext、image:4 varchar(max)、varbinary(max):8 reference)


使用二进制编辑器(如Visual Studio中的编辑器)删除前缀字节,所有操作都会正常运行。:-)

如果您有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);
}

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

你可以访问他们的网站,在那里获得免费软件,或者进行为期30天的完整版本试用。它正在下载并为SQL server选择Toad

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

我将添加此图标,以便其他希望使用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");
}
使用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

嗨,达斯汀-我能够使用命令输出文件,但我认为它不能正常工作。数据是序列化的.net对象。我知道数据是正确存储的,因为我有处理.net数据的进程。然而,当我尝试反序列化时,我得到一个错误,这意味着字节没有正确写入。思想?如果命令输出一个varbinary(max)值,那么实际的字节是写入磁盘的还是进程包括头等?使用-N选项似乎可以使这项工作正常在提示时使用以下选项:-输入字段XXX的文件存储类型[varbinary(max)]:-输入字段XXX的前缀长度[8]:0-输入字段XXX的长度[0]:-输入字段终止符[none]:-是否将此格式信息保存在文件中?[Y/n]nPrints out:SQLState=37000,NativeError=2812 Error=[Microsoft][ODBC驱动程序13 for SQL Server][SQL Server]找不到存储过程“sp_descripve_first_result_set”。您需要指定前缀长度0,而不是默认的8,这样文件长度就不会在文件数据之前作为前缀(头)写入。是否有效。。。?真的,所以
var context=this
将自动搜索您的sql server实例,登录,将找到正确的数据库,其中有一个图像表存在的方案。。。从来都不知道林帕德这么聪明!!你用过吗?看来不是这样。我猜irfandar和我只是在想象。是的,我使用它,是的,你的答案是正确的,但只有在你正确配置连接的情况下,但是你的答案中缺少这些信息,对于新的LinqPad用户来说,这看起来就像魔术一样。。。这是我要运行的唯一一点,可能需要启用OLE自动化过程。要启用OLE自动化过程,请使用:
sp\u configure'show advanced options',1
GO
重新配置
GO
sp\u配置“Ole自动化程序”,1
GO
重新配置免费Sql server的Toad?link?@Vilhelm你是否隶属于蟾蜍?@DavidWalschots否。我曾与蟾蜍一起在Oracle数据库上工作,但感到沮丧的是,我无法在MS Management Studio中完成同样的工作。然后我看到Toad有一个MSSQL版本,免费软件有这个功能,所以我现在用它作为MSSQL数据库的主编辑器。