如何使用SQL变量迭代XML节点

时间:2016-09-26 18:01:07

标签: sql-server xml sql-server-2008

我在SQL Server 2008中有这个XML:

DECLARE @xml xml = '<Root>
                      <Contacts>
                        <Contact name="John Doe" type="REG" other="value" />
                        <Contact name="Jane Doe" type="REG" other="value" />
                        <Contact name="Jennifer Doe" type="REG" other="value" />
                        <Contact name="Jane Doe" type="REG" other="value" />
                      </Contacts>
                    </Root>'

我想将类型的值更改为其他内容。我可以硬编码我想改变哪一个没问题。

SET @xml.modify('replace value of (/Root/Contacts/Contact)[1]/@type with "NEW"')
SELECT @xml

无论我在括号中放置什么价值,这都是“做对了”。 IOW,上面更改了第一个,将其更改为[3]更改第三个,等等。

我想改变所有这些,无论有多少或几乎没有。所以,我需要得到计数,然后使用变量迭代它们。获得计数很容易,但我无法使变量起作用。

IOW,这个用上面的[1]替换变量的XML不起作用。

DECLARE @i int = 1
SET @xml.modify('replace value of (/Root/Contacts/Contact)[sql:variable("@i")]/@type with "NEW"')
SELECT @xml

它给了我这个错误,它告诉我我做错了什么,但是我不能理解错误来找出我做错了什么

  

Msg 2337,Level 16,State 1,Line 14
  XQuery [modify()]:'replace'的目标必须至多是一个节点,找到'attribute(type,xdt:untypedAtomic)*'

当我即将点击“发布”时,我发现引用了一些内容,表示你必须使用position()才能在节点索引上使用变量,但示例是查询,而不是修改。这也行不通。

DECLARE @i int = 1
SET @xml.modify('replace value of (/Root/Contacts/Contact)[position()=sql:variable("@i")]/@type with "NEW"')
SELECT @xml

我毫不怀疑这很容易,但我在这里和其他地方搜索了如何使用sql:variable,几乎所有我发现的例子都将它用作替换中的值,不是索引(也没有“可能已经有你的答案的问题”帮助了。)我还在各个地方尝试了额外的括号等等,而且还没有能够达到神奇的组合。

使用@i?

使上述SET工作失败了

1 个答案:

答案 0 :(得分:4)

您自己的代码只能使用一个[1]。函数.modify()无法解释[sql:variable(...)] ...这可能是任何过滤器,即使是具有多个结果的过滤器......所以只需将其更改为:

DECLARE @xml xml = '<Root>
                      <Contacts>
                        <Contact name="John Doe" type="REG" other="value" />
                        <Contact name="Jane Doe" type="REG" other="value" />
                        <Contact name="Jennifer Doe" type="REG" other="value" />
                        <Contact name="Jane Doe" type="REG" other="value" />
                      </Contacts>
                    </Root>';
DECLARE @i int = 1
SET @xml.modify('replace value of (/Root/Contacts/Contact)[sql:variable("@i")][1]/@type with "NEW"')
SELECT @xml

但我会走另一条道路......您可能会将整个视图作为派生表阅读,并像这样重建XML:

SELECT
(
    SELECT c.value('@name','nvarchar(max)') AS [@name]
          --,c.value('@type','nvarchar(max)') AS [@type]
          ,'NEW' AS [@type]
          ,c.value('@other','nvarchar(max)') AS [@other]
    FROM @xml.nodes('/Root/Contacts/Contact') AS A(c)
    FOR XML PATH('Contact'),ROOT('Contact'),TYPE
)
FOR XML PATH('Root')

另一种方法是FLWOR:

SELECT @xml.query('
for $r in /Root/Contacts
    return <Root><Contacts>
    {
        for $c in /Root/Contacts/Contact
           return <Contact name="{$c/@name}" type="NEW" other="{$c/@other}"/>
    }
    </Contacts></Root>
')