我有一些varbinary数据存储在MS Sql Server 2005的表中。是否有人有SQL代码将查询作为输入(假设查询保证返回单列varbinary)并将字节输出到磁盘(每行一个文件?)我确信之前已经问了一千次,但谷歌搜索提出的主要是.net解决方案。我想要一个SQL解决方案。
答案 0 :(得分:35)
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
答案 1 :(得分:13)
您可以使用BCP,而不是T-SQL,但效果很好。
BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T
答案 2 :(得分:11)
我将这个添加到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");
}
答案 3 :(得分:5)
我知道它是一个旧帖子,但我弄清楚为什么以下不起作用以及如何解决它:
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/library/ms190779.aspx)
使用二进制编辑器(如Visual Studio中的编辑器)删除前缀字节,一切运行完美。 : - )
答案 4 :(得分:2)
如果你有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);
}
答案 5 :(得分:2)
只是另一种选择。您可以使用免费软件Toad for SQL server并直接从编辑器保存。
您可以访问他们的网站https://www.toadworld.com并获取免费软件或完整版的30天试用版。它位于下载并选择Toad for SQL server。
您在包含要保存图像的行上的Toad中执行常规select语句。 当您看到结果时,您可以单击字节图像列,如果这是PDF文档,则会在右侧看到PDF选项卡,或者在左侧看到图像选项卡。 单击选项卡时,您可以在底部看到保存徽标以保存图像或文件。
答案 6 :(得分:0)
SQL旨在处理数据库对象,因此从它的角度来看,其他任何东西都不存在。当然,像xp_cmdshell
这样的扩展程序允许您与操作系统进行交互,但它们是专有扩展,而不是T-SQL的一部分。
也许最接近的方法是使用FILESTREAM属性用于SQL Server 2008的二进制类型,它允许将某些列直接存储为文件夹中的文件而不是使用数据库:
注意 FILESTREAM存储设计用于维护数据库中的大型文件以提高性能,而不是允许直接访问文件(即T- SQL仍然没有文件系统的概念)。我认为,从SQL直接访问文件系统会破坏数据库的一些用途(主要是以结构化方式存储数据)。
所以我建议遵循Dustin的建议并使用像BCP或任何其他数据转储程序这样的工具。
答案 7 :(得分:0)
使用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