在SQL Server中查询XML文件

时间:2017-06-06 13:27:39

标签: sql-server xml

这是我的xml文件

<Detials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Parents>
    <Parent id="1234">
      <name>
        <firstname>ABC</firstname>
        <lastname>XYSX</lastname>
      </name>
    </Parent>
    <Parent id="1235">
      <name>
        <firstname>TFU</firstname>
        <lastname>GHY</lastname>
      </name>
    </Parent>
  </Parents>
  <Children>
    <Child id="457" Parentid="1234">
      <name>
        <cfirstname>JOHN</cfirstname>
        <clastname>SMITH</clastname>
      </name>
    </Child>
    <Child id="459" Parentid="1235">
      <name>
        <cfirstname>DAVID</cfirstname>
        <clastname>SMITH</clastname>
      </name>
    </Child>
  </Children>
</Detials>

我将它存储在一个表格中(使用批量插入)。

当我这样查询时

SELECT
    x.c.value('(./Parents/Parent/@id)[1]', 'nvarchar(4)' ) AS id
FROM 
    T1 s
CROSS APPLY 
    s.XMLData.nodes('Detials') AS x(c)

我得到结果

Id
----
1234

当我稍微改变它时

SELECT
    x.c.value('@id', 'nvarchar(4)' ) AS id
FROM 
    T1 s
CROSS APPLY 
    s.XMLData.nodes('/Detials/Parents/Parent') AS x(c)

我明白了:

Id
----
1234
1235

我只想查询结果如此

Parent_id | firstname | lastname | Child_id | Child_First_name | child_last_name 
----------+-----------+----------+----------+------------------+-----------
1234      | ABC       | XYSX     |    457   |      JOHN        | SMITH 
1235      | TFU       | GHY      |    459   |      DAVID       | SMITH 

我怎么能在查询中这样做?

在我的结果中我想要完全没有。的行数取决于Parentid。如果我的xml文件包含6个<parent id>,那么我的查询应该显示每个父ID的所有6行,并且如果Parentid在<child>中匹配,也会包含Childid的比较标签

谢谢,Jayendran

3 个答案:

答案 0 :(得分:1)

您在正确的轨道上,但这需要在两个结果集Parent / Children

上进行左连接

示例

Declare @T1 table (ID int,XMLData xml) 
Insert Into @T1 values
(1,'<Detials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Parents><Parent id="1234"><name><firstname>ABC</firstname><lastname>XYSX</lastname></name></Parent><Parent id="1235"><name><firstname>TFU</firstname><lastname>GHY</lastname></name></Parent></Parents><Children><Child id="457" Parentid="1234"><name><cfirstname>JOHN</cfirstname><clastname>SMITH</clastname></name></Child><Child id="459" Parentid="1235"><name><cfirstname>DAVID</cfirstname><clastname>SMITH</clastname></name></Child></Children></Detials>')

Select A.ID
      ,B.*
 From  @T1 A
 Cross Apply (
                Select B1.Parent_id
                      ,B1.First_Name
                      ,B1.Last_Name
                      ,B2.Child_id  
                      ,B2.Child_First_name 
                      ,B2.child_last_name  
                 From  (
                        Select
                            Parent_id  = x.c.value('@id', 'nvarchar(4)' )
                           ,First_Name = x.c.value('(name/firstname)[1]','varchar(50)')
                           ,Last_Name  = x.c.value('(name/lastname)[1]','varchar(50)')
                        From @T1 s
                        Cross Apply s.XMLData.nodes('/Detials/Parents/Parent') AS x(c)
                       ) B1
                 Left Join  (
                        Select 
                            pt_id      = x.c.value('@Parentid', 'nvarchar(4)' )
                           ,Child_id   = x.c.value('@id', 'nvarchar(4)' )
                           ,Child_First_name  = x.c.value('(name/cfirstname)[1]','varchar(50)')
                           ,child_last_name   = x.c.value('(name/clastname)[1]','varchar(50)')
                        From @T1 s
                        Cross Apply s.XMLData.nodes('/Detials/Children/Child ') AS x(c)
                       ) B2
                   on  B1.Parent_id = B2.pt_id
             ) B

<强>返回

enter image description here

答案 1 :(得分:1)

您可以使用以下解决方案:

WITH ParsedXml
AS (
SELECT [type] = y.XmlCol.value('local-name(.)', 'NVARCHAR(128)'), 
    id = y.XmlCol.value('(@id)[1]', 'INT'), 
    fname = COALESCE( y.XmlCol.value('(name/firstname)[1]', 'NVARCHAR(100)'), y.XmlCol.value('(name/cfirstname)[1]', 'NVARCHAR(100)') ),
    lname = COALESCE( y.XmlCol.value('(name/lastname)[1]', 'NVARCHAR(100)'), y.XmlCol.value('(name/clastname)[1]', 'NVARCHAR(100)') ),
    Parentid = y.XmlCol.value('(@Parentid)[1]', 'INT')
FROM @x.nodes('*:Detials/*/*') y(XmlCol)
) 
SELECT *
FROM ParsedXml AS p/*arent*/ LEFT JOIN ParsedXml AS c/*hild*/ ON c.[type] = 'Child' AND p.id = c.Parentid
WHERE p.[type] = 'Parent' 

<强> Demo

或者这个:

SELECT p.*, 
    c_id = c.XmlCol.value('(@id)[1]', 'INT'), 
    c_fname = c.XmlCol.value('(name/cfirstname)[1]', 'NVARCHAR(100)'),
    c_lname = c.XmlCol.value('(name/clastname)[1]', 'NVARCHAR(100)')
FROM (
SELECT p_id = y.XmlCol.value('(@id)[1]', 'INT'), 
    p_fname = y.XmlCol.value('(name/firstname)[1]', 'NVARCHAR(100)'),
    p_lname = y.XmlCol.value('(name/lastname)[1]', 'NVARCHAR(100)')
FROM @x.nodes('*:Detials/Parents/Parent') y(XmlCol)
) AS p OUTER APPLY @x.nodes('*:Detials/Children/Child[@Parentid eq sql:column("p_id")]') c(XmlCol)

<强> Demo

答案 2 :(得分:0)

我会一次性解决这个问题:

SELECT Parent.ID
      ,p.value('(name/firstname/text())[1]','nvarchar(max)')
      ,p.value('(name/lastname/text())[1]','nvarchar(max)')
      ,c.value('@id','int')
      ,c.value('(name/cfirstname/text())[1]','nvarchar(max)')
      ,c.value('(name/clastname/text())[1]','nvarchar(max)')
FROM @xml.nodes('/Detials/Parents/Parent') AS A(p)
OUTER APPLY (SELECT p.value('@id','int')) AS Parent(ID)
OUTER APPLY @xml.nodes('/Detials/Children/Child[@Parentid=sql:column("Parent.ID")]') AS B(c);

诀窍是,通过ParentidAPPLY读入名为的列中。此值可用作谓词,以通过sql:column()获取子项。