Utilizzando XQuery di SQL Server 2005 selezionare tutti i nodi con un valore di attributo specifico o con tale attributo mancante

StackOverflow https://stackoverflow.com/questions/90023

  •  01-07-2019
  •  | 
  •  

Domanda

Aggiornamento:facendo un esempio molto più approfondito.

Le prime due soluzioni offerte erano proprio in linea con quanto stavo cercando di dire non fare.Non posso conoscere la posizione, deve essere in grado di guardare l'intero albero del documento.Quindi una soluzione in questo senso, con /Books/ specificato come contesto non funzionerà:

SELECT x.query('.') FROM @xml.nodes('/Books/*[not(@ID) or @ID = 5]') x1(x)

Domanda originale con un esempio migliore:

Utilizzando l'implementazione XQuery di SQL Server 2005 devo selezionare tutti i nodi in un documento XML, solo una volta ciascuno e mantenendo la loro struttura originale, ma solo se manca un particolare attributo o se quell'attributo ha un valore specifico (passato per parametro).La query deve anche funzionare sull'intero documento XML (asse discendente o autonomo) anziché selezionare a una profondità predefinita.

Vale a dire, ogni singolo nodo apparirà nel documento risultante solo se a esso e a tutti i suoi antenati manca l'attributo o se hanno l'attributo con un singolo valore specifico.

Per esempio:

Se questo fosse l'XML:

    DECLARE @Xml XML
    SET @Xml =
    N'
<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
    <Novel category="4">Novel4</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
      <Volume category="3">M-S</Volume>
      <Volume category="4">T-Z</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>
    '

Un parametro pari a 1 per la categoria comporterebbe quanto segue:

<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>

Un parametro pari a 2 per la categoria comporterebbe quanto segue:

<Library>
  <Novels>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
    </Encyclopedia>
  </Encyclopedias>
</Library>

So che XSLT è perfettamente adatto per questo lavoro, ma non è un'opzione.Dobbiamo realizzare tutto questo interamente in SQL Server 2005.Anche qualsiasi implementazione che non utilizza XQuery va bene, purché possa essere eseguita interamente in T-SQL.

È stato utile?

Soluzione

Dal tuo esempio non mi è chiaro cosa stai effettivamente cercando di ottenere.Vuoi restituire un nuovo XML con tutti i nodi eliminati tranne quelli che soddisfano la condizione?Se sì, allora questo sembra il lavoro per una trasformazione XSLT che non penso sia integrata in MSSQL 2005 (può essere aggiunta come UDF: http://www.topxml.com/rbnews/SQLXML/re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx).

Se devi solo restituire l'elenco dei nodi, puoi utilizzare questa espressione:

//Book[not(@ID) or @ID = 5]

ma ho l'impressione che non sia quello che ti serve.Sarebbe utile se potessi fornire un esempio più chiaro.

Modificare:Questo esempio è davvero più chiaro.Il meglio che ho trovato è questo:

SET @Xml.modify('delete(//*[@category!=1])')
SELECT @Xml

L'idea è di eliminare dall'XML tutti i nodi che non ti servono, così rimani con la struttura originale e i nodi necessari.Ho provato con i tuoi due esempi e ha prodotto il risultato desiderato.

Tuttavia modificare ha alcune restrizioni: sembra che tu non possa usarlo in un'istruzione select, deve modificare i dati sul posto.Se è necessario restituire tali dati con una selezione, è possibile utilizzare una tabella temporanea in cui copiare i dati originali e quindi aggiornare quella tabella.Qualcosa come questo:

INSERT INTO #temp VALUES(@Xml)
UPDATE #temp SET data.modify('delete(//*[@category!=2])')

Spero che aiuti.

Altri suggerimenti

La domanda non è del tutto chiara, ma è questo quello che stai cercando?

DECLARE @Xml AS XML
        SET @Xml =
        N'
        <Books>
                <Book ID="1">Book1</Book>
                <Book ID="2">Book2</Book>
                <Book ID="3">Book3</Book>
                <Book>Book4</Book>
                <Book ID="5">Book5</Book>
                <Book ID="6">Book6</Book>
                <Book>Book7</Book>
                <Book ID="8">Book8</Book>
        </Books>
        '
DECLARE @BookID AS INT
SET @BookID = 5
DECLARE @Result AS XML

SET @result = (SELECT @xml.query('//Book[not(@ID) or @ID = sql:variable("@BookID")]'))
SELECT @result
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top