将 varbinary 更新到现有 SQL 列(添加到现有图像)?

Posted

技术标签:

【中文标题】将 varbinary 更新到现有 SQL 列(添加到现有图像)?【英文标题】:Update var binary to existing SQL columns (Add to existing image)? 【发布时间】:2020-01-25 18:42:26 【问题描述】:

我有一张桌子City;我的Pic 列数据类型是varbinary(max)

我使用此代码更新我的图片列并工作(对于 1 张图片):

UPDATE City 
SET pic = 0xwed323422222222.... 
WHERE id = 4

但是如何更新Pic 列中的 3 张或更多图片? (添加到现有图像)

我的意思是我在表where id = 4 中只存储了 1 个二进制图像。如何在单列中保存多张图片?

【问题讨论】:

将多个图像存储在一个列中可能看起来是一个聪明的举措 - 但不要这样做!你应该永远不要将多个项目存储在一个列中——这只是在自找麻烦和长期维护问题。 如果我不在单列中存储多张图片,有些行有 40 张图片,有些有 3 张,有些有 10 张。所以我必须有 40 列来存储图像,我怎么知道每行要显示多少图像? 您似乎有设计问题。一行的一列应该包含表所表示的“事物”的一个且只有一个属性。我们不知道您存储城市的图片(或多张图片)的目标是什么,但为城市存储多张图片的正确设计是创建一个子表,该表具有您的城市表的外键。 tsql 中没有“数组”类型,我认为您在这里不恰当地尝试应用其他语言的概念。 @smor 我有 5000 个城市,如果我为任何将重负载加载到服务器以供用户上传或下载图片的城市创建子表。 您应该使用适当的关系模型:1 个城市可以链接到单独表格中的 n 张图片 - 每行一张图片。这是正确的方法 【参考方案1】:

您可以利用 xml(及其结构完整性)在单个列中以“半结构化”方式存储多个图像。您可以将“pic”列的数据类型更改为 xml 或将其保留为 varbinary(后者需要某种类型转换)。

以下示例假定“图像”列和“c:\testnew”文件夹(在 sql 实例上)的 varbinary 存储,其中包含 3 个图像(图像 [1..3].png)。

首先,为 cityid=1 的“图像”列加载两个图像,然后使用更新 .write() 将第三个图像附加到二进制数据(前 2 个图片)。 通过使用 xml.modify() 方法可以实现在 blob 中的特定位置删除图像或插入图像。

如果您真的需要/必须将多张图像存储在一行和一列中,所有这一切。

create table dbo.TestImages
(
    id int identity(1,1) constraint pkidTestImages primary key clustered(id),
    CityId int,
    ImagesBlobXml varbinary(max) --or xml
)
go


--insert two images from folder c:\testnew
insert into dbo.TestImages
(
    CityId, ImagesBlobXml
)

values (
1, 
cast((
select TheImage
from 
(
select *
from openrowset(bulk N'C:\testnew\image1.png', single_blob) as i(TheImage)
union all
select *
from openrowset(bulk N'C:\testnew\image2.png', single_blob) as i(TheImage)
--union all
--select *
--from openrowset(bulk N'C:\testnew\***.png', single_blob) as i(TheImage)
) as images
for xml path(''), type
) as varbinary(max))
);

select 'table content', *
from  dbo.TestImages;


--retrieve images (2)
select 'images in blob, initial insert', t.id, t.CityId, i.bin.value('.', 'varbinary(max)') as TheImage
from
(
select *, cast(ImagesBlobXml as xml) as ImagesBlobXmlXML
from dbo.TestImages 
) as t
cross apply t.ImagesBlobXmlXML.nodes('TheImage') as i(bin);


--append new image
update t
set ImagesBlobXml .WRITE( --note:write cannot be used on NULL values
cast((
select TheImage
from 
(
select *
from openrowset(bulk N'C:\testnew\image3.png', single_blob) as i(TheImage)
) as images
for xml path(''), type
) as varbinary(max)) , 
null, 0 --write() append
)
from dbo.TestImages as t
where CityId = 1;


--retrieve the images (3)
select 'images in blob, after update_append', t.id, t.CityId, i.bin.value('.', 'varbinary(max)') as TheImage
from
(
select *, cast(ImagesBlobXml as xml) as ImagesBlobXmlXML
from dbo.TestImages 
) as t
cross apply t.ImagesBlobXmlXML.nodes('TheImage') as i(bin);

--check for any diff
select i.bin.value('.', 'varbinary(max)') as TheImage
from
(
select *, cast(ImagesBlobXml as xml) as ImagesBlobXmlXML
from dbo.TestImages 
) as t
cross apply t.ImagesBlobXmlXML.nodes('TheImage') as i(bin)
except
select TheImage
from 
(
select *
from openrowset(bulk N'C:\testnew\image1.png', single_blob) as i(TheImage)
union all
select *
from openrowset(bulk N'C:\testnew\image2.png', single_blob) as i(TheImage)
union all
select *
from openrowset(bulk N'C:\testnew\image3.png', single_blob) as i(TheImage)
) as images;
go

--cleanup
drop table dbo.TestImages;
go

【讨论】:

以上是关于将 varbinary 更新到现有 SQL 列(添加到现有图像)?的主要内容,如果未能解决你的问题,请参考以下文章

C#/SQL:从 DataGridView 到 Picturebox 的 Varbinary(max) 列

Perl DBI / FreeTDS / SQL-Server:如何插入/更新 BLOB varbinary(max) 数据?

VarBinary(max) 在 SQL Azure 上更新非常慢

sql将一个表中的某一列数据更新到另一个表中

将列添加到现有 SQL Server 表 - 含义

将新列添加到现有表中并使用 PL/SQL 中游标中的值更新它们