'替换'的目标必须至多是一个节点

时间:2014-04-22 03:00:20

标签: sql xml sql-server-2012 xquery

我试图修改XML值但继续收到消息

  

替换的目标必须至多是一个节点,找到属性(prefType,xdt:untypedAtomic)

首先是我的XML

<preferences>
 <categories>
<category id="1" prefType="2">
  <subcat id="1" prefType="2" />
  <subcat id="2" prefType="2" />
  <subcat id="3" prefType="2" />
  <subcat id="77" prefType="2" />
</category>
<category id="2" prefType="2">
  <subcat id="9" prefType="2" />
  <subcat id="10" prefType="2" />
  <subcat id="11" prefType="2" />
  <subcat id="12" prefType="2" />
  <subcat id="13" prefType="2" />
  <subcat id="14" prefType="2" />
  <subcat id="17" prefType="2" />
  <subcat id="78" prefType="2" />
  <subcat id="101" prefType="2" />
</category>
<category id="3" prefType="2">
  <subcat id="18" prefType="2" />
  <subcat id="19" prefType="2" />
  <subcat id="20" prefType="2" />
</category>
</categories>
</preferences>

我的代码

declare @XMLinput as XML;
declare @custXML as XML;

declare @subcatid as nvarchar(3);
declare @interest as nvarchar(8);
declare @newValue as varchar(1);
declare @cnt as int;

set @XMLinput = '<preferences><categoryId>73</categoryId><interestLevel>POSITIVE</interestLevel></preferences>';

-- get the subcatid and interest level
SET @subcatid =  @XMLinput.value('(//preferences/categoryId)[1]','nvarchar(3)');
SET @interest =  @XMLinput.value('(//preferences/interestLevel)[1]','nvarchar(20)');

SET @newValue = 
CASE @interest
    WHEN 'POSITIVE' THEN '1'
    WHEN 'NEGATIVE' THEN  '3'
    ELSE '2'
END;

set @custXML = (select Preferences from Customer_Preferences where custID=11584);
select @custXML.exist('//preferences/categories/category/subcat[@id=sql:variable("@subcatid")]');

if (@@ROWCOUNT > 0)

BEGIN TRY
    BEGIN TRAN;
    set @cnt = CAST(CAST(@custXML.query('count(//preferences/categories/category/subcat[@id=(sql:variable("@subcatid"))])') AS VARCHAR) AS INT);

    -- replace the value
    UPDATE Customer_Preferences
        SET preferences.modify('
            replace value of 
                (//*/subcat[@id=sql:variable("@subcatid")]/@prefType[1]) 
            with sql:variable("@newValue")
            ')
    where CustID = 11584;

    COMMIT TRAN;
END TRY
BEGIN CATCH
    select XACT_STATE() as 'XACT_STATE', @@TRANCOUNT as '@@TRANCOUNT';
    if @@TRANCOUNT > 0 ROLLBACK TRANSACTION;

END CATCH

select preferences from Customer_Preferences where custid=11584
SELECT XACT_STATE() as 'XACT_STATE', @@TRANCOUNT AS '@@TRANCOUNT'

我尝试删除sql变量并用固定值替换它们但仍然遇到同样的问题。我还尝试删除所有XML子类,除了发生同一个错误。

经过3个小时的工作并且没有任何地方,我非常感谢你的帮助。

1 个答案:

答案 0 :(得分:2)

正如进一步参考(虽然你已经解决了你自己的问题)对于有类似问题的其他人:这是实际出错的地方:错误信息已经表明替换目标最多只能有一个值(意味着你可以一次只能替换一个值。)

但是,(//*/subcat[@id=sql:variable("@subcatid")]/@prefType[1])会产生一系列结果。字面意思是指每个subcat元素和选择名称为prefType 的第一个属性。这实际上没有多大意义,因为XML元素不能具有多个具有相同名称的属性,因此在没有[1]谓词的情况下查询将是相同的。

您可能想要写的是:给我每个prefType元素的每个subcat属性,并仅返回整个结果集中的第一个。这正是您的工作查询正在执行的操作:(//*/subcat[@id=sql:variable("@subcatid")]/@prefType)[1]