2017-06-19 7 views
1

Ich versuche herauszufinden, wie XML eine sich wiederholende Struktur zu verarbeiten. Im folgenden Beispiel sollte Herr Smith zwei Kinder haben (Mike und Tom) und Frau Magoo sollte keine Kinder haben. Tom, Mr. Smiths Kind, hat ein Kind namens Sally, das das Enkelkind von Mr. Smith ist. Frau Magoo, die keine Kinder hat, hat auch keine Enkelkinder.SQL Parsing XML mit sich wiederholender Struktur

DECLARE @tableXML table (
ID int NOT NULL, 
XMLdata xml NOT NULL 
); 

DECLARE @testXML xml 
SET @testXML = 
'<parent> 
    <name>Mr. Smith</name> 
    <child> 
     <name>Mike</name> 
     <child /> 
    </child> 
    <child> 
     <name>Tom</name> 
     <child> 
      <name>Sally</name> 
     </child> 
    </child> 
</parent> 
<parent> 
    <name>Ms. Magoo</name> 
    <child> 
     <name /> 
     <child /> 
    </child> 
</parent>' 

INSERT INTO @tableXML VALUES 
(1, @testXML); 

SELECT 
    IsNull(parent.p.value('self::node()','varchar(100)'),Null) AS [Parent], 
    IsNull(children.c.value('self::node()','varchar(100)'),Null) AS [Child], 
    IsNull(grandChildren.g.value('self::node()','varchar(100)'),Null) AS [Grandchild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent/name') AS parent (p) 
CROSS APPLY parent.p.nodes('/parent/child/name') AS children (c) 
CROSS APPLY children.c.nodes('/parent/child/child/name') AS grandChildren (g) 

Die Ergebnismenge der oben genannten ist:

Parent | Child | Grandchild 
--------------------------------- 
Mr. Smith Mike  Sally 
Mr. Smith Tom  Sally 
Mr. Smith    Sally 
Ms. Magoo Mike  Sally 
Ms. Magoo Tom  Sally 
Ms. Magoo    Sally 

Das Ergebnis sollte:

Parent | Child | Grandchild 
--------------------------------- 
Mr. Smith Mike  
Mr. Smith Tom  Sally 
Ms. Magoo  

Gedanken?

Danke! Mike

+0

Schön, dass Du hast einen * copy'n'paste * Testcode erstellt! +1 von meiner Seite – Shnugo

+0

Ist das in der Tiefe begrenzt (in diesem Fall: 3 Stufen), oder suchen Sie einen generischen Ansatz (könnte Sally auch Kinder haben)? – Shnugo

+0

Btw: Was ist mit dem 'IsNull()'? Wenn es "NULL" ist, gibt man 'NULL' zurück? – Shnugo

Antwort

0

es auf diese Weise versuchen:

SELECT 
    p2.lin.value('(./name)[1]','varchar(100)') AS [Parent], 
    p3.lin.value('self::node()','varchar(100)') AS [Child], 
    p3.lin.value('(./child)[1]','varchar(100)') AS [GrandChild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent') AS p2(lin) 
CROSS APPLY p2.lin.nodes('child') AS p3(lin) 
GO 
 
Parent | Child | GrandChild 
:-------- | :------- | :--------- 
Mr. Smith | Mike  |   
Mr. Smith | TomSally | Sally  
Ms. Magoo |   |   

dbfiddle here

+0

Wenn Sally einen Bruder (ein Kind unter "Tom") hätte, würden Sie in allen Fällen den ersten lesen. Sie vermissen die '.nodes()' für die dritte Ebene ... – Shnugo

0

Sie waren in der Nähe ...

Mit CROSS APPLY xyz.nodes() ca Sie n tauchen tiefer und tiefer in verschachtelte Strukturen ein. Aber Sie müssen dies wie von einer relativen Adresse (aktuelle Position) innerhalb Ihrer Struktur denken.

Mit einer Zeile wie

CROSS APPLY parent.p.nodes('/parent/child/name') AS children (c) 

... Sie wieder rechts unten von der Wurzel zu lesen, nicht an dem Start bei parent.p

es so versuchen:

SELECT 
    IsNull(parent.p.value('(name/text())[1]','varchar(100)'),Null) AS [Parent], 
    IsNull(children.c.value('(name/text())[1]','varchar(100)'),Null) AS [Child], 
    IsNull(grandChildren.g.value('(name/text())[1]','varchar(100)'),Null) AS [Grandchild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent') AS parent (p) 
CROSS APPLY parent.p.nodes('child') AS children (c) 
CROSS APPLY children.c.nodes('child') AS grandChildren (g);