2012-10-27 3 views
7
declare @xmlsample xml = 
'<root> 
    <solution> 
     <solutionnumber>1</solutionnumber> 
      <productgroup> 
       <productcategory> 
        <price>100</price> 
        <title>Some product</title> 
        <tax>1</tax> 
       </productcategory> 
      </productgroup> 
      <productcategory2> 
        <price>200</price> 
        <title>Some other product</title> 
        <tax>2</tax> 
      </productcategory2> 
    </solution> 
    <solution> 
     <solutionnumber>2</solutionnumber> 
      <productcategory2> 
        <price>200</price> 
        <title>Some other product</title> 
        <tax>2</tax> 
      </productcategory2> 
    </solution> 
</root>' 

SELECT 
    --T.C.value('(./ancestor::ns1:solutionNumber)[1]', 'varchar(50)') AS solutionnumber ?? no clue 
    T.C.value('(price)[1]', 'numeric(18,2)') AS price 
    ,T.C.value('(title)[1]', 'varchar(50)') AS title 
    ,T.C.value('(tax)[1]', 'numeric(18,2)') AS tax 
FROM @xmlsample.nodes('//node()[title]') AS T(C) 

Eine Darstellung der XML, die ich versuche, in SQL Server 2008 r2 zu zerkleinern. Ich finde den "title" -Knoten und schnappe mir die Werte, die ich in der Produktkategorie benötige. Jetzt möchte ich die "Lösungsnummer" erhalten, aber dies könnte ein oder mehrere Elternknoten über dem Produkt sein, da es bestimmte Produkt- "Gruppen" gibt.SQL Server .nodes() XML übergeordnete Knoten nach Name

Wie würde ich gehen, überprüfen Sie die Elternknoten nach Namen ("Lösungsnummer"), bis ich es finde? Danke für jegliche Hilfe.

+0

falsche Terminologie meinerseits. Ich suche immer noch nach "Lösungsnummer". – duffn

Antwort

2

Vielleicht ging ich rückwärts darüber. Mehrfache Kreuzanträge erledigen die Aufgabe. Dank einiger Hilfe in einem anderen Forum.

SELECT 
    --T.C.value('(./ancestor::ns1:solutionNumber)[1]', 'varchar(50)') AS solutionnumber ?? no clue 
    m.c.value('(solutionnumber)[1]', 'int') as solutionnumber 
    ,T.C.value('(price)[1]', 'numeric(18,2)') AS price 
    ,T.C.value('(title)[1]', 'varchar(50)') AS title 
    ,T.C.value('(tax)[1]', 'numeric(18,2)') AS tax 
FROM @xmlsample.nodes ('//solution') as m (c) 
cross apply m.c.nodes ('.//node()[title]') as t(C) 
2

Es gibt keinen direkten Weg zu meinem Wissen. Sie können jedoch COALESCE verwenden Sie Ihren Weg zur Suche nach oben:

SELECT 
    COALESCE(T.C.value('../solutionnumber[1]', 'INT'), 
      T.C.value('../../solutionnumber[1]', 'INT'), 
      T.C.value('../../../solutionnumber[1]', 'INT')) solutionnumber, 
    T.C.value('(price)[1]', 'numeric(18,2)') AS price, 
    T.C.value('(title)[1]', 'varchar(50)') AS title, 
    T.C.value('(tax)[1]', 'numeric(18,2)') AS tax 
    FROM 
    @xmlsample.nodes('//node()[title]') AS T (C) 

Beachten Sie, dass <solutionnumber> ist wirklich ein Geschwister eines der Vorfahren und nicht ein Vorfahr selbst.

Bei dieser Lösung müssen Sie die maximale Tiefe im Voraus kennen.


Sie können auch diese Lösung verwenden, wenn Sie lieber nach vorn gehen, als nach hinten:

SELECT solutionNodes.solutionNode.value('solutionnumber[1]','INT') AS solutionnumber, 
    T.C.value('(price)[1]', 'numeric(18,2)') AS price, 
    T.C.value('(title)[1]', 'varchar(50)') AS title, 
    T.C.value('(tax)[1]', 'numeric(18,2)') AS tax 
FROM @xmlsample.nodes('//solution') AS solutionNodes (solutionNode) 
CROSS APPLY (SELECT solutionNodes.solutionNode.query('.')) solutions(solutionXML) 
CROSS APPLY solutions.solutionXML.nodes('//node()[title]') T (C) 

Es nutzt die Tatsache, dass die <solutionnumber> -Tag ein direktes Kind eines ist <solution> Tag. Zuerst werden alle <solution> Tags gefunden. Als alle seine Titel werden Nachkommen mit einem Kreuz gefunden. Da Sie die Knotenfunktion auf einem Knoten nicht verwenden können, gibt es die Berechnung von "query ('.')" Dazwischen.

Abgesehen von der oben genannten Lösung kann dieser Abstand zwischen dem <solution> tag und dem <title> Tag eingehalten werden.

1

SQL Server unterstützt nicht rückwärts auf den Vorfahren, also hier ist ein Umweg von caching der Zeiger auf einen Vorfahren beim Abstieg in das XML.

declare @xmlsample xml = 
'<root> 
    <solution> 
     <solutionnumber>1</solutionnumber> 
      <productgroup> 
       <productcategory> 
        <price>100</price> 
        <title>Some product</title> 
        <tax>1</tax> 
       </productcategory> 
      </productgroup> 
      <productcategory2> 
        <price>200</price> 
        <title>Some other product</title> 
        <tax>2</tax> 
      </productcategory2> 
    </solution> 
    <solution> 
     <solutionnumber>2</solutionnumber> 
      <productcategory2> 
        <price>200</price> 
        <title>Some other product</title> 
        <tax>2</tax> 
      </productcategory2> 
    </solution> 
</root>'; 

WITH Xml_CTE AS 
(
    SELECT node.query('*') AS children, 
      node.value('fn:local-name(.)','varchar(100)') localName, 
      node.exist('title') IsTitleParent, 
      CAST(null as xml) as solution 
     FROM @xmlsample.nodes('/*') AS root(node) 
    UNION ALL 
    SELECT node.query('*') AS children, 
      node.value('fn:local-name(.)','varchar(100)') localName, 
      node.exist('title') IsTitleParent, 
      CASE WHEN node.value('fn:local-name(.)', 'varchar(100)') = 'solution' 
       THEN node.query('.') 
       ELSE solution END 
     FROM Xml_CTE x 
CROSS APPLY x.children.nodes('*') AS child(node) 
) 
SELECT solution.value('(solution/solutionnumber/text())[1]', 'int') solutionNumber 
     ,children.value('(price)[1]', 'numeric(18,2)') price 
     ,children.value('(title)[1]', 'varchar(50)') title 
     ,children.value('(tax)[1]', 'numeric(18,2)') tax 
    FROM Xml_CTE 
WHERE IsTitleParent = 1 -- matches .nodes('//node()[title]') 
OPTION (MAXRECURSION 0); 
0

Dies wird perfekt funktionieren ...

Declare @SomeXML XML 
SET @SomeXML = '<SomeValue>GGGG</SomeValue><SomeValue>MMMM</SomeValue><SomeValue>AAA</SomeValue>' 

select ROW_NUMBER() over (order by b), b.value('.', 'varchar(50)') 
from @SomeXML.nodes('(/SomeValue)') AS a(b)