SQL - 使用INNER JOIN获取XML,修改XML

时间:2012-09-04 12:46:33

标签: sql-server-2008 sqlxml

我在SQL Server 2008中有一个表,它将XML数据存储在XML列中。典型的XML片段是:

<validation>
    <Field1 author="56234" date="20120101" />
    <Field2 author="23232" date="20120101" />
        [...etc...]
</validation>

我正在尝试解决的问题 - 我无法看到如何做 - 是通过INNER JOIN选择此数据到另一个表并修改结果集中的XML数据,即我得到的这样:

<validation>
    <Field1 author="56234" date="20120101" authorFullName="Bob Smith" />
    <Field2 author="23232" date="20120101" authorFullName="Jane Hill" />
        [...etc...]
</validation>

现在我知道我可以做CROSS APPLY直接将XML数据拉入记录集和内连接 - 例如:

select xmldata.a, people.personname
    from xmldata
        cross apply xmldata.x.nodes('/validation/node()') vdata(fielddata)
        inner join people 
            on people.personid = vdata.fielddata.value('@author','NVARCHAR(20)')

但我真正想做的是返回原始XML但添加了新属性,将people.PersonName映射到新的@authorFullName属性。

我无法弄清楚语法(或者即使它确实可行)。我假设我cross applymodify进行insert attribute - 基于

select xmldata.a, xmldata.x
    from xmldata
        cross apply xmldata.x.modify('insert attribute authorFullName {sql:column("people.personfullname")} into /validation/node()')
        inner join people 
            on people.personid = [...what goes here?...]

但是正确的语法正在逃避我。我越来越认为这是不可能的,我最好在两个查询中执行此操作并将结果合并到非SQL业务逻辑中。

1 个答案:

答案 0 :(得分:1)

您不能在select语句中使用modify

来自modify() Method (xml Data Type)

  

xml数据类型的modify()方法只能在SET中使用   UPDATE语句的子句。

我认为你有两种选择。

  1. 粉碎XML并使用for xml path以您希望的方式重建XML文档,并在适当的位置插入人名。
  2. 将XML解压缩到变量并使用set @XML.modify(insert...插入人名。
  3. 如果你选择第二个选项,你必须使用while循环,因为insert (XML DML)中的expression2必须是一个单独的节点。

    选项2的代码看起来像这样。

    declare @XML xml
    declare @C int
    declare @PersonName varchar(50)
    declare @PersonID int
    
    -- Store your XML in a XML variable
    set @XML = 
    '<validation>
        <Field1 author="56234" date="20120101" />
        <Field2 author="23232" date="20120101" />
    </validation>'
    
    -- Get number of nodes to be modified
    set @C = @XML.value('count(/validation/*)', 'int')
    
    -- For each node
    while @C > 0
    begin
      -- Get person id from XML
      set @PersonID = @XML.value('(/validation/*[sql:variable("@C")]/@author)[1]', 'int')
    
      -- Get person name
      select @PersonName = personname
      from people
      where personid = @PersonID 
    
      if @@rowcount = 1
      begin
        -- add person name to XML
        set @XML.modify('insert attribute authorFullName {sql:variable("@PersonName")} 
                            into (/validation/*[sql:variable("@C")])[1]')
      end
    
      -- next node
      set @C = @C - 1
    end