Usando XQuery de SQL Server 2005, seleccione todos los nodos con un valor de atributo específico o con ese atributo faltante

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

  •  01-07-2019
  •  | 
  •  

Pregunta

Actualizar:dando un ejemplo mucho más completo.

Las dos primeras soluciones ofrecidas coincidían con lo que estaba tratando de decir. no hacer.No puedo saber la ubicación, es necesario poder ver todo el árbol de documentos.Entonces, una solución similar a esta, con /Books/ especificado como contexto no funcionará:

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

Pregunta original con mejor ejemplo:

Al utilizar la implementación XQuery de SQL Server 2005, necesito seleccionar todos los nodos en un documento XML, solo una vez cada uno y manteniendo su estructura original, pero solo si les falta un atributo particular o si ese atributo tiene un valor específico (pasado por parámetro).La consulta también tiene que funcionar en todo el documento XML (eje descendiente o propio) en lugar de seleccionar en una profundidad predefinida.

Es decir, cada nodo individual aparecerá en el documento resultante sólo si a él y a cada uno de sus ancestros les falta el atributo, o si tienen el atributo con un único valor específico.

Por ejemplo:

Si este fuera el 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 parámetro de 1 para categoría daría como resultado esto:

<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 parámetro de 2 para la categoría daría como resultado esto:

<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>

Sé que XSLT es perfecto para este trabajo, pero no es una opción.Tenemos que lograr esto completamente en SQL Server 2005.Cualquier implementación que no utilice XQuery también está bien, siempre que se pueda realizar completamente en T-SQL.

¿Fue útil?

Solución

A partir de tu ejemplo, no me queda claro qué es lo que realmente estás tratando de lograr.¿Quiere devolver un nuevo XML con todos los nodos eliminados excepto aquellos que cumplen la condición?En caso afirmativo, este parece el trabajo para una transformación XSLT que no creo que esté integrada en MSSQL 2005 (se puede agregar como una UDF: http://www.topxml.com/rbnews/SQLXML/re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx).

Si solo necesita devolver la lista de nodos, puede usar esta expresión:

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

pero me da la impresión de que no es lo que necesitas.Sería útil si pudiera proporcionar un ejemplo más claro.

Editar:De hecho, este ejemplo es más claro.Lo mejor que pude encontrar es esto:

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

La idea es eliminar del XML todos los nodos que no necesitas, para quedarte con la estructura original y los nodos necesarios.Probé con sus dos ejemplos y produjo el resultado deseado.

Sin embargo modificar tiene algunas restricciones: parece que no se puede usar en una declaración de selección, tiene que modificar los datos en su lugar.Si necesita devolver dichos datos con una selección, puede usar una tabla temporal en la que copiar los datos originales y luego actualizar esa tabla.Algo como esto:

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

Espero que ayude.

Otros consejos

La pregunta no está muy clara, pero ¿es esto lo que estás buscando?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top