2012-10-27 12 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) 

Una rappresentazione dell'XML che sto tentando di distruggere in SQL Server 2008 r2. Trovo il nodo "titolo" e prendo i valori che ho bisogno che sono nella categoria di prodotto. Ora vorrei ottenere il "numero della soluzione", tuttavia questo potrebbe essere uno o più nodi principali sopra il prodotto in quanto vi sono determinati "gruppi" di prodotti.SQL Server .nodes() Nodi padre XML per nome

Come dovrei controllare i nodi padre per nome ("numero di soluzione") finché non lo trovo? Grazie per l'assistenza.

+0

terminologia non corretta da parte mia. Ancora cercando "solutionnumber", comunque. – duffn

risposta

2

Forse stavo andando indietro. La croce multipla farà il lavoro. Grazie ad un po 'di assistenza su un altro 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

Non c'è un modo diretto per la mia conoscenza. Tuttavia, è possibile utilizzare COALESCE per cercare il vostro senso:

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) 

noti che <solutionnumber> è davvero un fratello di uno degli antenati e non un antenato in sé.

Questa soluzione richiede di conoscere la profondità massima in anticipo.


È inoltre possibile utilizzare questa soluzione, se si preferisce andare avanti che indietro:

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) 

Esso utilizza il fatto che il <solutionnumber> tag è un figlio diretto di un> tag <solution. Innanzitutto vengono trovati tutti i tag <solution>. Di tutti i suoi discendenti del titolo si trovano con una croce si applicano. Poiché non è possibile utilizzare la funzione dei nodi su un nodo, c'è il calcolo di "query ('.')" Nel mezzo.

Oltre alla soluzione sopra indicata, questa può gestire qualsiasi distanza tra il tag <solution> tag <title>.

1

SQL Server non supporta l'arretramento dell'antenato, quindi ecco un modo indiretto di caching il puntatore a un antenato durante la discesa nell'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

Questo funziona perfettamente ...

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)