【发布时间】:2013-12-24 23:18:04
【问题描述】:
这就是我想要做的:基本上将 XML 发送到 SQL Server 以更新/插入(合并)我的数据作为我的代码中的“保存”函数。
如果我使用以下 XML 在 XML 中发送一个“项目”,我已经成功地做到了这一点:
<root>
<Formula1>
<M_iFormula1Id>0</M_iFormula1Id>
<M_bDataInUse>0</M_bDataInUse>
<M_bActive>1</M_bActive>
<M_lstItem>
<M_iItemId>0</M_iItemId>
<M_iItemTypeId>1</M_iItemTypeId>
<M_sItemValue>German</M_sItemValue>
<M_iRaceId>1</M_iRaceId>
<M_iDriverId>50</M_iDriverId>
</M_lstItem>
</Formula1>
</root>
在这个存储过程中:
ALTER PROCEDURE [dbo].[spFormula1_Save]
@Formula1Xml xml--Formula1 as xml
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF DATALENGTH(@Formula1Xml) = 0
RETURN 0
BEGIN TRANSACTION
BEGIN TRY
DECLARE @hDoc INT
EXEC sp_xml_preparedocument @hDoc OUTPUT, @Formula1Xml
-------------------
--Formula1 Table
-------------------
DECLARE @Formula1Id bigint = 0;
MERGE INTO Formula1 AS tab
USING
OPENXML (@hDoc, '/root/Formula1', 2)
WITH (
M_iFormula1Id bigint,
M_bDataInUse bit,
M_bActive bit
) AS [xml]
ON (tab.Formula1Id = [xml].[M_iFormula1Id])
WHEN MATCHED THEN UPDATE SET tab.DataInUse = [xml].M_bDataInUse,
tab.Active = [xml].M_bActive,
@Formula1Id = [xml].M_iFormula1Id
WHEN NOT MATCHED THEN INSERT (DataInUse,
Active)
VALUES([xml].M_bDataInUse,
[xml].M_bActive
);
IF(@Formula1Id = 0)--then we haven''t updated so get inserted rowid
BEGIN
SET @Formula1Id = SCOPE_IDENTITY();--get the inserted identity
END
-------------------
--Formula1Item Table
-------------------
MERGE INTO Formula1Item AS tab
USING
OPENXML (@hDoc, '/root/Formula1/M_lstItem', 2)
WITH (
M_iItemId bigint,
M_iItemTypeId bit,
M_sItemValue varchar(1000),
M_iRaceId int,
M_iDriverId int
) AS [xml]
ON (tab.ItemId = [xml].M_iItemId)
WHEN MATCHED THEN UPDATE SET tab.ItemTypeId = [xml].M_iItemTypeId,
tab.ItemValue = [xml].M_sItemValue,
tab.RaceId = [xml].M_iRaceId,
tab.DriverId = [xml].M_iDriverId
WHEN NOT MATCHED THEN INSERT (Formula1Id,
ItemTypeId,
ItemValue,
RaceId,
DriverId)
VALUES(@Formula1Id,
[xml].M_iItemTypeId,
[xml].M_sItemValue,
[xml].M_iRaceId,
[xml].M_iDriverId
);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH;
END
当我在 XML 中有多个记录时,@Formula1Id 被设置为插入第一个合并语句中的最后一个记录,因此 XML 中的所有子数据都使用此 ID 合并,这意味着所有子数据都属于一个父级!
<root>
<Formula1>
<M_iFormula1Id>0</M_iFormula1Id>
<M_bDataInUse>0</M_bDataInUse>
<M_bActive>1</M_bActive>
<M_lstItem>
<M_iItemId>0</M_iItemId>
<M_iItemTypeId>1</M_iItemTypeId>
<M_sItemValue>German</M_sItemValue>
<M_iRaceId>1</M_iRaceId>
<M_iDriverId>50</M_iDriverId>
</M_lstItem>
</Formula1>
<Formula1>
<M_iFormula1Id>0</M_iFormula1Id>
<M_bDataInUse>0</M_bDataInUse>
<M_bActive>1</M_bActive>
<M_lstItem>
<M_iItemId>0</M_iItemId>
<M_iItemTypeId>1</M_iItemTypeId>
<M_sItemValue>French</M_sItemValue>
<M_iRaceId>2</M_iRaceId>
<M_iDriverId>50</M_iDriverId>
</M_lstItem>
</Formula1>
</root>
有什么方法可以保持外键关系正确。
也许 Merge 语句是错误的方式,但它似乎是一次处理大量插入/更新的最佳方式。
也许您可以建议一种替代方法-主要标准是性能,因为可能有数千个要“保存”的项目-我尝试查看 SqlBulkCopy 但这似乎也不能很好地处理外键关系。 .. 我知道我可以一次保存到一张表,但是如果“保存”的一部分出错,我就会失去 ROLLBACK 功能!
非常感谢任何帮助/建议。提前致谢。
【问题讨论】:
标签: sql sql-server xml merge