如何使用XQuery连接相同的节点值

时间:2011-02-15 07:16:26

标签: sql-server xml concatenation

我正在尝试使用XQuery将XML插入到表中。有些节点是多个节点,但表中只有一列,所以我需要连接相同的节点。

如何迭代"INSERT ... SELECT ... FROM @xmlDoc.nodes ..."类型的查询。

以下是我的xml文件的示例

<Persons>
    <Person>
        <FirstName>aaa</FirstName>
        <LastName>bbb</LastName>
        <DocumentNumber>AA 1234</DocumentNumber>
        <DocumentNumber>BB 1234</DocumentNumber>
        <WorkPlace>AAA Ltd</WorkPlace>
        <WorkPlace>BBB Ltd</WorkPlace>
    </Person>
    <Person>
        <FirstName>ccc</FirstName>
        <LastName>ddd</LastName>
        <DocumentNumber>CCC 1234</DocumentNumber>
        <DocumentNumber>DDD 1234</DocumentNumber>
        <DocumentNumber>EEE 1234</DocumentNumber>     
        <WorkPlace>CCC Ltd</WorkPlace>
        <WorkPlace>DDD Ltd</WorkPlace>
    </Person>
</Persons>

感谢。

2 个答案:

答案 0 :(得分:2)

这是一个使用cte的版本,首先在xml列中隔离DocumentNumber和WorkPlace,然后使用for xml path('')来连接值。

declare @xml xml
set @xml =
'
<Persons>
    <Person>
        <FirstName>aaa</FirstName>
        <LastName>bbb</LastName>
        <DocumentNumber>AA 1234</DocumentNumber>
        <DocumentNumber>BB 1234</DocumentNumber>
        <WorkPlace>AAA Ltd</WorkPlace>
        <WorkPlace>BBB Ltd</WorkPlace>
    </Person>
    <Person>
        <FirstName>ccc</FirstName>
        <LastName>ddd</LastName>
        <DocumentNumber>CCC 1234</DocumentNumber>
        <DocumentNumber>DDD 1234</DocumentNumber>
        <DocumentNumber>EEE 1234</DocumentNumber>     
        <WorkPlace>CCC Ltd</WorkPlace>
        <WorkPlace>DDD Ltd</WorkPlace>
    </Person>
</Persons>
'

;with cte as
(
  select
    p.value('FirstName[1]', 'varchar(50)') as FirstName,
    p.value('LastName[1]', 'varchar(50)') as LastName,
    p.query('DocumentNumber') as docXML,
    p.query('WorkPlace') as workXML
  from
    @xml.nodes('Persons/Person') p(p)
)
select
  FirstName,
  LastName,
  (select d.value('.', 'varchar(100)')+' '
   from cte.docXML.nodes('DocumentNumber') d(d)
   for xml path('')) as DocumentNumber,
  (select w.value('.', 'varchar(100)')+' '
   from cte.workXML.nodes('WorkPlace') w(w)
   for xml path('')) as WorkPlace
from cte    

答案 1 :(得分:1)

您的XML组织非常糟糕......问题在于<DocumentNumber><WorkPlace>实体的多个条目直接位于<Person>内,而不在其自己的“容器”节点内。

这使得解析得非常困难.....

如果您只想抓取名字,可以使用:

DECLARE @input XML = '<Persons>
    <Person>
        <FirstName>aaa</FirstName>
        <LastName>bbb</LastName>
        <DocumentNumber>AA 1234</DocumentNumber>
        <DocumentNumber>BB 1234</DocumentNumber>
        <WorkPlace>AAA Ltd</WorkPlace>
        <WorkPlace>BBB Ltd</WorkPlace>
    </Person>
    <Person>
        <FirstName>ccc</FirstName>
        <LastName>ddd</LastName>
        <DocumentNumber>CCC 1234</DocumentNumber>
        <DocumentNumber>DDD 1234</DocumentNumber>
        <DocumentNumber>EEE 1234</DocumentNumber>     
        <WorkPlace>CCC Ltd</WorkPlace>
        <WorkPlace>DDD Ltd</WorkPlace>
    </Person>
</Persons>'

SELECT
    Person.value('(FirstName)[1]', 'varchar(50)') 'First Name',
    Person.value('(LastName)[1]', 'varchar(50)') 'Last Name'
FROM
    @input.nodes('/Persons/Person') AS Persons(Person)

当然,在选择存储信息之前,您还可以执行INSERT INTO dbo.YourTable(FirstName, LastName)

但是又一次:尝试将这些<DocumentNumber><WorkPlace>节点设置为正确的格式真的很难.....你要么最终复制数据,要么你必须做第二次第三次解析传递以正确存储这些东西。