【问题标题】:Update rows in Database using XML data使用 XML 数据更新数据库中的行
【发布时间】:2013-03-19 18:31:19
【问题描述】:

这是我第一次使用 XML 将数据插入表中。我将前端的数据(所有 Datagridview 行)保存到 xml 文件中,并将其发送到数据库以插入表 SD_ShippingDetails.Below是用于读取 XML 数据和保存数据的查询。从查询中可以看到,我正在删除相关的 ShippingID 详细信息并再次插入。(从 SD_ShippingDetails WHERE ShippingID=@ShippingID 删除)。我们可以更新 SD_ShippingDetails 中的现有行吗通过从 XML 中获取数据。如果是,请帮助我查询。

CREATE PROCEDURE SD_Insert_ShippingDetails    
@PBMXML as varchar(Max),      
@ShippingID as INT      

AS      
BEGIn      


declare @i int      

exec sp_xml_preparedocument @i output,@PBMXML      



DELETE FROM SD_ShippingDetails WHERE ShippingID=@ShippingID      


INSERT INTO  SD_ShippingDetails(ShippingID,Weight,Height,TotalBoxes,Price)      
SELECT ShippingID,Weight,Height,TotalBoxes,Price FROM OPENXML(@i,'Root/ShippingBox',2)      
WITH (      
ShippingID int,Weight varchar(20),Height varchar(20),TotalBoxes varchar(20),Price numeric(18,2))    



exec sp_xml_removedocument @i      

END 

谢谢。

【问题讨论】:

  • 您可以将 XML 数据填充到临时/变量表中,然后使用合并插入/更新现有表。你知道怎么做吗?
  • 嗨,伙计,你能帮我查询一下吗,因为我不知道这样做。
  • 您需要提供一些 XML。
  • 如果您使用的是 SQL 2005,则不能像其他人指出的那样使用 Merge。 :(
  • 是的,它已在 sql 2008 中引入 :-(

标签: c# sql-server sql-server-2005 datagridview


【解决方案1】:

您使用的是 SQL Server 2005,因此您可以使用 XML 数据类型而不是 openxml,因此此答案使用该数据类型。解决方案不需要使用 XML 数据类型。如果你愿意,你可以使用 openxml 重写。

您在 cmets 中指定 SD_ShippingDetails 中有一个 ID 标识字段(我假设这是主键),但您还说 ShippingID 和 Weight 的组合是唯一的。这给我们留下了一个看起来像这样的表结构。

create table dbo.SD_ShippingDetails
(
  ID int identity primary key,
  ShippingID int not null,
  Weight varchar(20) not null,
  Height varchar(20),
  TotalBoxes varchar(20),
  Price numeric(18,2),
  unique (ShippingID, Weight)
);

存储过程首先需要更新 SD_ShippingDetails 中已存在的所有行,然后再插入缺失的行。

create procedure dbo.SD_Insert_ShippingDetails
  @PBMXML as xml
as

update dbo.SD_ShippingDetails 
set Height = T.N.value('(Height/text())[1]', 'varchar(20)'),
    TotalBoxes = T.N.value('(TotalBoxes/text())[1]', 'varchar(20)'),
    Price = T.N.value('(Price/text())[1]', 'numeric(18,2)')
from @PBMXML.nodes('Root/ShippingBox') as T(N)
where ShippingID = T.N.value('(ShippingID/text())[1]', 'int') and
      Weight = T.N.value('(Weight/text())[1]', 'varchar(20)');

insert into dbo.SD_ShippingDetails(ShippingID, Weight, Height, TotalBoxes, Price)
select T.N.value('(ShippingID/text())[1]', 'int'),
       T.N.value('(Weight/text())[1]', 'varchar(20)'),
       T.N.value('(Height/text())[1]', 'varchar(20)'),
       T.N.value('(TotalBoxes/text())[1]', 'varchar(20)'),
       T.N.value('(Price/text())[1]', 'numeric(18,2)')
from @PBMXML.nodes('Root/ShippingBox') as T(N)
where not exists (
                 select *
                 from dbo.SD_ShippingDetails
                 where ShippingID = T.N.value('(ShippingID/text())[1]', 'int') and
                       Weight = T.N.value('(Weight/text())[1]', 'varchar(20)')
                 );

SQL Fiddle

【讨论】:

  • 给不了解的dotnet开发者的一个小建议。我想当我们创建一个带有XML参数的StoredProcedure时,我们不需要在前端发送参数作为XElement(这是XML类型)。给SQLDBTYPE.XML 形式的参数和字符串形式的值。
【解决方案2】:

如果您有 Sql Server 2005,最好将值放在 #temp 或 @variables 表中。

在 2008 年及更高版本中,您可以搭载 MERGE 功能。

http://msdn.microsoft.com/en-us/library/bb522522(v=sql.105).aspx

这是一个很好的 xml 粉碎链接。注意,您使用的是旧版本的 OPENXML。那是一个更多的 Sql Server 2000 命令。查看下面 Plamen 的博客,了解 2005 及更高版本的语法。

http://pratchev.blogspot.com/2007/06/shredding-xml-in-sql-server-2005.html

【讨论】:

  • 嗨,谢谢伙计。虽然我并不完全理解我写的查询。作为紧急事项,我已经从网上复制了它并且它工作正常。我已经通过链接并且不太了解。我会尝试找到一种写作方法使用链接更新查询。
  • 第 1 步是将数据放入 @ 变量或 #temp 表中。我会先从@变量表开始。然后第 2 步是执行更新......并将真实表的 PK 与 @variable 表的 PK(主键)匹配。是的,更新匹配的行比删除所有内容并重新插入更好。
  • 我不知道如何实现这一点。而不是使用 XML 概念,如果我通过在前端循环插入 Datagridview 中的每一行会怎样。它会影响性能吗?。有一件事是肯定会增加对数据库的调用次数。
  • 您在谈论 RBAR “Row by Agonizing Row”。尝试考虑“基于集合”,而不是 RBAR。以后你会感谢我的。
  • PS 是的,它会影响性能。每次 RBAR 操作后都必须重建任何索引。 :
【解决方案3】:

我会将您的 XML 填充到变量表中,然后使用 Update 语句和带有 Not ExistsInsert

如果你有 SQL 2008,你可以用这个替换你的删除和插入语句......

MERGE   SD_ShippingDetails AS Target
USING  (SELECT  ShippingID,
                Weight,
                Height,
                TotalBoxes,
                Price 
        FROM    OPENXML(@i,'Root/ShippingBox',2)      
                WITH   (ShippingID int,
                        Weight varchar(20),
                        Height varchar(20),
                        TotalBoxes varchar(20),
                        Price numeric(18,2)) ) AS source (ShippingID,Weight,Height,TotalBoxes,Price)
        ON (target.ShippingID = source.ShippingID)
WHEN    MATCHED THEN 
        UPDATE  SET Weight = source.Weight,
                    Height = source.Height,
                    TotalBoxes = source.TotalBoxes,
                    Price = source.Price
WHEN    NOT MATCHED THEN    
        INSERT (ShippingID,Weight,Height,TotalBoxes,Price)
        VALUES (source.ShippingID,source.Weight,source.Height,source.TotalBoxes,source.Price);

【讨论】:

  • 他将他的问题标记为“Sql Server 2005”,因此我相信为什么 MERGE (upsert) 对他不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 2013-07-10
相关资源
最近更新 更多