如何使用SQL从XML DML中的节点传递索引值

时间:2017-02-07 16:55:30

标签: sql sql-server xml dml

从SQL Server中的XML DML开始,目前还不错,但我正面临着这一挑战。我需要遍历存储在SQL Server中的XML数据中的一些已定义节点。

已经将此作为参考检查,它给出了一个线索,但我仍然没有弄清楚如何将XML变量作为XML DML Reference中的索引发送。

假设以下XML数据:

<est_mat>

所以我要看的是遍历所有<pos>个节点并从10开始替换--starting of code declare @cnt int = 10 declare @totalchildren varchar(300) declare @pos int = 1 --returns the number of nodes SET @totalchildren = (SELECT (XMLData.value('count(/materials/est_mat)', 'int')) FROM TABLE_XMLFiles WHERE myref = 173) WHILE @cnt < @totalchildren BEGIN --PRINT @cnt UPDATE TABLE_XMLFiles SET XMLData.modify('replace value of (/materials/est_mat/pos[sql:variable("@pos")])[[1]] with sql:variable("@cnt")') WHERE myref = 173 SET @cnt = @cnt + 1 SET @pos = @pos + 10 END --end of code 属性,然后下一个节点将是20,依此类推。

到目前为止,我有这个:

SET XMLData.modify('replace value of (/materials/est_mat/pos/text())[sql:variable("@pos")] 
                    with sql:variable("@cnt")')

错误:

  

XQuery [BinControl_XMLFiles.XMLData.modify()]:&#39;替换&#39;的目标必须是非元数据属性或具有简单类型内容的元素,找到&#39;元素(pos,xdt:untyped)?&#39;

问题是:如何将SQL变量作为索引位置发送如下:

sql:variable("@cnt")

因为我替换它的值通过以{{1}}这样的方式发送它 - 已经尝试过并且有效但我仍然没有弄清楚如何通过索引上下文发送变量。

提前感谢您的关注。

1 个答案:

答案 0 :(得分:2)

为什么不忽略exsting <pos> - 元素并重新构建XML?

DECLARE @xml XML=
N'<materials>
  <est_mat>
    <pos>20</pos>
    <item>BOX</item>
    <qty>0.004</qty>
  </est_mat>
  <est_mat>
    <pos>30</pos>
    <item>xxx-xxx-xxx01</item>
    <qty>1</qty>
  </est_mat>
  <est_mat>
    <pos>40</pos>
    <item>xxx-xxx-xxx02</item>
    <qty>1</qty>
  </est_mat>
</materials>';

SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) * 10 AS pos 
      ,em.value(N'item[1]',N'nvarchar(max)') AS item
      ,em.value(N'qty[1]',N'decimal(16,4)') AS qty 
FROM @xml.nodes(N'/materials/est_mat') AS A(em)
FOR XML PATH('est_mat'),ROOT('materials')

更新您的后续问题

(请避免变色龙问题!)

可以通过两个组合步骤查询您的结构。一个查询选择所有现有节点,未调用<materials> ,然后将上述查询添加为子元素。

提示 XML中的相应日期格式为ISO8601。您的价值02092017取决于文化因素,因此您应该避免这种情况。更好2017-02-092017-02-09T00:00:00(如果不是9月2日:-))

DECLARE @xml XML= 
N'<order>
  <orderbook>
    <date> 02092017 </date>
  </orderbook>
  <materials>
    <est_mat>
      <pos>20</pos>
      <item>BOX</item>
      <qty>0.004</qty>
    </est_mat>
    <est_mat>
      <pos>30</pos>
      <item>xxx-xxx-xxx01</item>
      <qty>1</qty>
    </est_mat>
    <est_mat>
      <pos>40</pos>
      <item>xxx-xxx-xxx02</item>
      <qty>1</qty>
    </est_mat>
  </materials>
</order>';

SELECT @xml.query(N'/order/*[local-name()!="materials"]') AS [*]
      ,(
        SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) * 10 AS pos 
              ,em.value(N'item[1]',N'nvarchar(max)') AS item
              ,em.value(N'qty[1]',N'decimal(16,4)') AS qty 
        FROM @xml.nodes(N'order/materials/est_mat') AS A(em)
        FOR XML PATH('est_mat'),ROOT('materials'),TYPE
       ) 
FOR XML PATH(N'order');

注意:可能会更改XML的内部节点顺序......