read - Al utilizar XQuery de SQL Server 2005, seleccione todos los nodos con un valor de atributo específico, o con ese atributo que falta
xml.value sql server (2)
La pregunta no es 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
Actualización: dando un ejemplo mucho más completo.
Las primeras dos soluciones ofrecidas estaban en línea con lo que estaba tratando de decir que no hiciera. No puedo saber la ubicación, debe poder ver todo el árbol de documentos. Entonces, una solución en esta línea, con / Books / specified, ya que el contexto no funcionará:
SELECT x.query(''.'') FROM @xml.nodes(''/Books/*[not(@ID) or @ID = 5]'') x1(x)
Pregunta original con mejor ejemplo:
Usando la implementación de XQuery de SQL Server 2005, necesito seleccionar todos los nodos en un documento XML, solo una vez cada uno y mantener su estructura original, pero solo si les falta un atributo particular, o ese atributo tiene un valor específico (pasado por parámetro). La consulta también debe funcionar en todo el documento XML (eje descendiente o auto) en lugar de seleccionarse a una profundidad predefinida.
Es decir, cada nodo individual aparecerá en el documento resultante solo si a él y a cada uno de sus antepasados le falta el atributo o si tiene 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 la categoría resultaría en 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 resultaría en 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 use XQuery también está bien, siempre y cuando se pueda hacer completamente en T-SQL.
No es claro para mí, por tu ejemplo, lo que realmente estás tratando de lograr. ¿Desea 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é incorporada 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. Ayudaría si puedes dar un ejemplo más claro.
Editar : 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 necesita, para que permanezca con la estructura original y los nodos necesarios. Probé con tus dos ejemplos y produjo el resultado deseado.
Sin embargo, modificar tiene algunas restricciones: parece que no puede usarlo en una declaración de selección, tiene que modificar los datos en su lugar. Si necesita devolver esos datos con un seleccionar, podría 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.