2011-12-11 11 views
5

Tengo algunos problemas usando los métodos exist() y value() en SQL Server 2008.SQL existir servidor XML()

Mi XML tiene el siguiente aspecto:

<?xml version="1.0" encoding="UTF-8"?> 
<library> 
    <branches> 
     <branch> 
      <codelib>1</codelib> 
      <name>Campus</name> 
     </branch> 
     <branch> 
      <codelib>2</codelib> 
      <name>47th</name> 
     </branch> 
     <branch> 
      <codelib>3</codelib> 
      <name>Mall</name> 
     </branch>    
    </branches> 
    <books> 
     <book type="SF"> 
      <codb>11</codb> 
      <title>Robots</title> 
      <authors> 
       <author>author1 robots</author> 
       <author>author2 robots</author> 
      </authors> 
      <price>10</price> 
      <stocks> 
       <branch codelib="1" amount="10"/> 
       <branch codelib="2" amount="5"/> 
       <branch codelib="4" amount="15"/> 
      </stocks> 
      <from>20</from> 
      <to>30</to> 
     </book> 
     <book type="poetry"> 
      <codb>12</codb> 
      <title>Poetry book</title> 
      <authors> 
       <author>AuthorPoetry</author> 
      </authors> 
      <price>14</price> 
      <stocks> 
       <branch codelib="1" amount="7"/> 
       <branch codelib="2" amount="5"/> 
      </stocks> 
      <from>25</from> 
      <to>40</to> 
     </book>  
     <book type="children"> 
      <codb>19</codb> 
      <title>Faitytales</title> 
      <authors>    
       <author>AuthorChildren</author>    
      </authors> 
      <price>20</price> 
      <stocks> 
       <branch codelib="1" amount="10"/> 
       <branch codelib="3" amount="55"/> 
       <branch codelib="4" amount="15"/> 
      </stocks> 
      <from>70</from> 
      <to>75</to> 
     </book>  
     <book type="literature"> 
      <codb>19</codb> 
      <title>T</title> 
      <authors> 
       <author>A</author>     
      </authors> 
      <price>17</price> 
      <stocks> 
       <branch codelib="1" amount="40"/> 
      </stocks> 
      <from>85</from> 
      <to>110</to> 
     </book> 
    </books> 
</library> 

Teniendo en cuenta este XML, tengo que escribir una SELECT cláusula que utilizará query(), value() y exist() 2 veces cada uno, como mínimo. Ni siquiera puedo usar query() y exist() en el mismo SELECT, ya que parece que la cláusula WHERE no tiene ningún efecto en absoluto.

Por ejemplo, quiero recuperar todos los <branch> elementos que son los niños del libro con el tipo SF, pero la instrucción de selección

declare @genre varchar(15) 
    set @genre = 'SF' 
    SELECT XMLData.query('//branch') from TableA 
    WHERE XMLData.exist('//book[./@type = sql:variable("@genre")]') = 1 

recupera todos los <branch> elementos, no sólo las del objetivo libro. No puedo entender qué pasa con mi selección. Asimismo, le agradecería un pequeño ejemplo con query(), exist() y value() en la misma selección (es posible tener anidado instrucciones select en SQL XML?)

Respuesta

7

Bueno, su expresión XPath aquí es el "culpable":

query('//branch') 

Esto dice: seleccione todos<branch> nodos de todo el documento. Simplemente está haciendo lo que le está diciendo que haga, realmente ...

¿Qué pasa con esta consulta aquí?

SELECT 
    XMLData.query('/library/books/book[@type=sql:variable("@genre")]//branch') 
FROM dbo.TableA 

Eso sería recuperar todos los <branch> subnodos del nodo <book> que tiene type="SF" como un atributo ....

¿Qué está tratando de lograr con su query(), value()exist() y todos en el mismo comunicado ?? Muy posiblemente, se puede hacer mucho más fácil ...

También: Creo que estás malinterpretando lo que hace .exist() en SQL Server XQuery. Si usted tiene su declaración aquí:

SELECT (some columns) 
FROM dbo.TableA 
WHERE XMLData.exist('//book[@type = sql:variable("@genre")]') = 1 

que está básicamente diciendo a SQL Server para recuperar todas las filas de dbo.TableA donde el XML almacenado en XMLData contiene un nodo <book type=.....> - que está seleccionando filas de la tabla - NO aplicar una selección del contenido de la columna XMLData ...

+0

No es lo que quiero, pero tengo que usar tanto query(), value() y existir() en la misma instrucción. Es por eso que quiero hacer algún tipo de filtrado como en T-SQL, SELECCIONAR ... DONDE ... puede algo así como declaraciones SELECT anidadas, si eso es posible. Solo quiero un ejemplo sobre cómo lograr algo así – joanna

3

El XML que ha proporcionado no se presta a una declaración exist. Si tenía varias declaraciones XML y necesitaba encontrar aquella donde contenía algún valor, entonces la declaración habría sido más relevante.

La cláusula where que proporcionó solo comprueba si la condición existe y, si lo hace, selecciona todos los elementos branches, no solo aquel en que la condición es verdadera. Por ejemplo, el siguiente (obviamente) no devuelve nada:

SELECT @xmldata.query('//branch') from TableA 
WHERE @xmldata.exist('//book[./@type = "BLAH"]') = 1 

Pero aquí es algo para demostrar que puede utilizar los tres en una instrucción de selección.

SELECT T.c.query('./title').value('.', 'varchar(250)') as title, 
     T.c.exist('.[@type eq "SF"]') as IsSF 
    from @xmldata.nodes('//book') T(c) 
+0

El SELECCIONADO que proporcionó está cerca de lo que necesito, TNX. Un último problema ... ¿es posible tener algo como SELECT ... WHERE x = (SELECT..WHERE), de modo que pueda usar value(), exist() y query() 2 veces? Básicamente, ¿una selección (con las 3 funciones) que filtrará algunos valores, y luego otra que usa los nodos filtrados? – joanna

0

Disculpas si esto se ha hecho tarde pero acabo de ver esta publicación.

Es más eficiente con XML filtrar utilizando el operador cross apply para filtrar al nodo requerido y luego seleccionar la consulta de los nodos devueltos. Para consultar los nodos secundarios también debe incluir la raíz. en la consulta, entonces en este caso .//branch en lugar de // branch.

declare @genre varchar(15) = 'SF' 
select l.query('.//branch') from TableA 
cross apply XmlData.nodes('library/books/book[@type=sql:variable("@genre")]') n (l) 

Todavía se puede añadir la cláusula existe si quieres, pero esto va a agregar una sobrecarga innecesaria adicional

WHERE XMLData.exist('//book[./@type = sql:variable("@genre")]') = 1 

Espero que esto ayude. D