Está en la página 1de 10

FLWOR (instruccin e iteracin de XQuery)

SQL Server 2012 Otras versiones

Este tema an no ha recibido ninguna valoracin - Valorar este tema XQuery define la sintaxis de iteracin FLWOR. FLWOR es el acrnimo de for, let, where, order by y return. Una instruccin FLWOR est formada por cuatro partes: Una o varias clusulas FOR que enlazan una o varias variables de iteracin a secuencias de entrada. Las secuencias de entrada pueden ser otras expresiones XQuery como expresiones XPath. Se trata de secuencias de nodos o de valores atmicos. Las secuencias de valores atmicos se pueden construir con literales o funciones constructoras. SQL Server no admite como secuencias de entrada los nodos XML construidos. Una clusula let opcional. Esta clusula asigna un valor a la variable para una iteracin concreta. La expresin asignada puede ser una expresin XQuery, como una expresin XPath, y puede devolver una secuencia de nodos o una secuencia de valores atmicos. Las secuencias de valores atmicos se pueden construir con literales o con funciones constructoras. SQL Server no admite los nodos XML construidos como secuencias de entrada. Una variable de iteracin. Esta variable puede tener una asercin de tipo opcional mediante la palabra clave as. Una clusula opcional where. Esta clusula aplica un predicado de filtro en la iteracin. Una clusula opcional order by. Una expresin return. La expresin de la clusula return construye el resultado de la instruccin FLWOR.

Por ejemplo, la consulta siguiente se repite en los elementos <Step> de la primera ubicacin de fabricacin y devuelve el valor de cadena de los nodos < Step>: declare @x xml set @x='<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" > <Location LocationID="L1" > <Step>Manu step 1 at Loc 1</Step> <Step>Manu step 2 at Loc 1</Step> <Step>Manu step 3 at Loc 1</Step> </Location> <Location LocationID="L2" > <Step>Manu step 1 at Loc 2</Step> <Step>Manu step 2 at Loc 2</Step> <Step>Manu step 3 at Loc 2</Step> </Location>

</ManuInstructions>' SELECT @x.query(' for $step in /ManuInstructions/Location[1]/Step return string($step) ') El resultado es el siguiente: Manu step 1 at Loc 1 Manu step 2 at Loc 1 Manu step 3 at Loc 1 La consulta siguiente es parecida a la anterior, a diferencia de que se especifica en la columna Instructions, una columna xml con tipo, de la tabla ProductModel. La consulta siguiente se repite en todos los pasos de fabricacin, los elementos <step>, en la primera ubicacin de centro de trabajo de un producto determinado. SELECT Instructions.query(' declare namespace AWMI="http://schemas.microsoft.com/sqlserver/2004/07/adv enture-works/ProductModelManuInstructions"; for $Step in //AWMI:root/AWMI:Location[1]/AWMI:step return string($Step) ') as Result FROM Production.ProductModel where ProductModelID=7 Observe lo siguiente en la consulta anterior:

$Step es la variable de iteracin. La expresin de ruta de acceso, //AWMI:root/AWMI:Location[1]/AWMI:step,


genera la secuencia de entrada. Se trata de la secuencia del nodo de elemento secundario <step> del primer nodo de elemento <Location>. La clusula de predicado opcional, where, no se utiliza. La expresin return devuelve un valor de cadena del elemento <step>.

string (funcin de XQuery) se utiliza para recuperar el valor de cadena del nodo <step>. ste es el resultado parcial: Insert aluminum sheet MS-2341 into the T-85A framing tool. Attach Trim Jig TJ-26 to the upper and lower right corners of the aluminum sheet. .... A continuacin se exponen ejemplos de las secuencias de entrada adicionales permitidas: declare @x xml set @x='' SELECT @x.query(' for $a in (1, 2, 3) return $a') -- result = 1 2 3 declare @x xml set @x='' SELECT @x.query(' for $a in

for $b in (1, 2, 3) return $b return $a') -- result = 1 2 3 declare @x xml set @x='<ROOT><a>111</a></ROOT>' SELECT @x.query(' for $a in (xs:string( "test"), xs:double( "12" ), data(/ROOT/a )) return $a') -- result test 12 111 SQL Server no admite las secuencias heterogneas. En concreto, no se admiten las secuencias que contienen una mezcla de valores atmicos y nodos. La iteracin se utiliza a menudo junto con la sintaxis de Construccin de XML para transformar formatos XML, tal como se muestra en la consulta siguiente. En la base de datos de ejemplo AdventureWorks, las instrucciones de fabricacin almacenadas en la columna Instructions de la tabla Production.ProductModel tienen la forma siguiente: <Location LocationID="10" LaborHours="1.2" SetupHours=".2" MachineHours=".1"> <step>describes 1st manu step</step> <step>describes 2nd manu step</step> ... </Location> ... La consulta siguiente construye un nuevo XML al que se devuelven los elementos <Location> con los atributos de ubicacin de centro de trabajo como elementos secundarios: <Location> <LocationID>10</LocationID> <LaborHours>1.2</LaborHours> <SetupHours>.2</SteupHours> <MachineHours>.1</MachineHours> </Location> ... Esta es la consulta: SELECT Instructions.query(' declare namespace AWMI="http://schemas.microsoft.com/sqlserver/2004/07/a dventure-works/ProductModelManuInstructions"; for $WC in /AWMI:root/AWMI:Location return <Location> <LocationID> { data($WC/@LocationID) } </LocationID> <LaborHours> { data($WC/@LaborHours) } </LaborHours> <SetupHours> { data($WC/@SetupHours) } </SetupHours> <MachineHours> { data($WC/@MachineHours) } </MachineHours> </Location> ') as Result FROM Production.ProductModel where ProductModelID=7

Observe lo siguiente en la consulta anterior: La instruccin FLWOR recupera una secuencia de elementos <Location> para un producto determinado. data (funcin de XQuery) se utiliza para extraer el valor de cada atributo de modo que se agregue al XML resultante como nodos de texto en lugar de atributos. La expresin de la clusula RETURN construye el XML deseado.

ste es un resultado parcial: <Location> <LocationID>10</LocationID> <LaborHours>2.5</LaborHours> <SetupHours>0.5</SetupHours> <MachineHours>3</MachineHours> </Location> <Location> ... <Location> ...

Usar la clusula let


Puede utilizar la clusula let para asignar nombre a las expresiones que se repiten y poder hacer referencia a ellas por medio de la variable asignada. La expresin asignada a una variable let se insertar en la consulta cada vez que se haga referencia a la variable en la consulta. Esto significa que la instruccin no se ejecutar una sola vez, sino tantas veces como se haga referencia a la expresin. En la base de datos AdventureWorks2012 , las instrucciones de fabricacin contienen informacin sobre las herramientas requeridas y la ubicacin donde se utilizan. La consulta siguiente utiliza la clusula let para hacer una lista de las herramientas necesarias para generar un modelo de produccin, as como las ubicaciones en que se necesita cada herramienta. SELECT Instructions.query(' declare namespace AWMI="http://schemas.microsoft.com/sqlserver/2004/07/a dventure-works/ProductModelManuInstructions"; for $T in //AWMI:tool let $L := //AWMI:Location[.//AWMI:tool[.=data($T)]] return <tool desc="{data($T)}" Locations="{data($L/@LocationID)}"/> ') as Result FROM Production.ProductModel where ProductModelID=7

Usar la clusula where


Se puede utilizar la clusula where para filtrar los resultados de una iteracin. Esto se muestra en el ejemplo siguiente.

El proceso de fabricacin de una bicicleta incluye una serie de ubicaciones de centro de trabajo. Cada una define una secuencia de pasos de fabricacin. La consulta siguiente recupera nicamente las ubicaciones de centro de trabajo que fabrican un modelo de bicicleta y tienen menos de tres pasos de fabricacin. Es decir, tienen menos de tres elementos <step>. SELECT Instructions.query(' declare namespace AWMI="http://schemas.microsoft.com/sqlserver/2004/07/a dventure-works/ProductModelManuInstructions"; for $WC in /AWMI:root/AWMI:Location where count($WC/AWMI:step) < 3 return <Location > { $WC/@LocationID } </Location> ') as Result FROM Production.ProductModel where ProductModelID=7 Observe lo siguiente en la consulta anterior: La palabra clave where utiliza la funcin count() para contar el nmero de elementos secundarios <step> de cada ubicacin de centro de trabajo. La expresin return construye el XML deseado a partir de los resultados de la iteracin.

El resultado es el siguiente: <Location LocationID="30"/> El resultado de la expresin de la clusula where se convierte en un valor booleano mediante las reglas siguientes, en el orden especificado. Se trata de las mismas reglas que se aplican para los predicados en las expresiones de ruta de acceso, con la diferencia de que no se admiten los enteros: 1. 2. 3. 4. Si la expresin where devuelve una secuencia vaca, su valor booleano efectivo ser False. Si la expresin where devuelve un valor de tipo booleano simple, ste ser el valor booleano efectivo. Si la expresin where devuelve una secuencia que incluye al menos un nodo, el valor booleano efectivo ser True. De lo contrario, provocar un error esttico.

Enlace de diversas variables en FLWOR


Puede tener una sola expresin FLWOR que enlace diversas variables a secuencias de entrada. En el ejemplo siguiente, la consulta se especifica con una variable xml sin tipo.La expresin FLOWR devuelve el primer elemento secundario < Step> de cada elemento <Location>. declare @x xml set @x='<ManuInstructions ProductModelID="1" ProductModelName="SomeBike" > <Location LocationID="L1" > <Step>Manu step 1 at Loc 1</Step>

<Step>Manu step 2 at Loc 1</Step> <Step>Manu step 3 at Loc 1</Step> </Location> <Location LocationID="L2" > <Step>Manu step 1 at Loc 2</Step> <Step>Manu step 2 at Loc 2</Step> <Step>Manu step 3 at Loc 2</Step> </Location> </ManuInstructions>' SELECT @x.query(' for $Loc in /ManuInstructions/Location, $FirstStep in $Loc/Step[1] return string($FirstStep) ') Observe lo siguiente en la consulta anterior: La expresin for define las variables $Loc y $FirstStep. Las expresiones two, /ManuInstructions/Location y $FirstStep in $Loc/Step[1], estn correlacionadas: los valores de $FirstStep dependen de los valores de $Loc. La expresin asociada con $Loc genera una secuencia de elementos <Location>. Por cada elemento <Location>, $FirstStep genera una secuencia de un elemento <Step>, un singleton. $Loc se especifica en la expresin asociada con la variable $FirstStep.

El resultado es el siguiente: Manu step 1 at Loc 1 Manu step 1 at Loc 2 La consulta siguiente es parecida, salvo que se especifica con la columna Instructions, una columna xml con tipo, de la tabla ProductModel. La Construccin de XML (XQuery)se utiliza para generar el XML deseado. SELECT Instructions.query(' declare default element namespace "http://schemas.microsoft.com/sqlserve r/2004/07/adventure-works/ProductModelManuInstructions"; for $WC in /root/Location, $S in $WC/step return <Step LocationID= "{$WC/@LocationID }" > { $S/node() } </Step> ') as Result FROM Production.ProductModel WHERE ProductModelID=7 Observe lo siguiente en la consulta anterior: La clusula for define dos variables, $WC y $S. La expresin asociada con $WC genera una secuencia de ubicaciones de centro de trabajo para la fabricacin de un modelo de bicicleta. La expresin de ruta de acceso asignada a la variable $S genera una secuencia de pasos para cada secuencia de ubicaciones de centro de trabajo de $WC.

La instruccin devuelta construye un XML con un elemento <Step> que incluye el paso de fabricacin y el LocationID como su atributo. La declaracin declare default element namespace se utiliza en el prlogo de XQuery para que todas las declaraciones de espacio de nombres del XML resultante aparezcan en el elemento superior. Esto facilita la lectura del resultado. Para obtener ms informacin acerca de los espacios de nombres predeterminados, veaControlar espacios de nombres en XQuery.

Este es el resultado parcial: <Step xmlns= "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductMo delManuInstructions" LocationID="10"> Insert <material>aluminum sheet MS-2341</material> into the <tool>T85A framing tool</tool>. </Step> ... <Step xmlns= "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Product ModelManuInstructions" LocationID="20"> Assemble all frame components following blueprint <blueprint>1299</blueprint>. </Step> ...

Usar la clusula order by


La ordenacin en XQuery se realiza usando la clusula order by en la expresin FLWOR. Las expresiones de ordenacin que se pasan a la clusula order by deben devolver valores cuyos tipos son vlidos para el operador gt. Cada expresin de ordenacin debe dar como resultado una secuencia de singleton con un elemento. De forma predeterminada, la ordenacin se realiza en orden ascendente. Podr especificar opcionalmente un orden ascendente o descendente para cada expresin de ordenacin.

Nota

Las comparaciones de ordenacin en valores de cadena realizadas mediante la implementacin de XQuery intercalacin de puntos de cdigo Unicode binarios.
La consulta siguiente recupera todos los nmeros de telfono de un cliente determinado de la columna AdditionalContactInfo. Los resultados se ordenan por nmero de telfono. USE AdventureWorks2012; GO SELECT AdditionalContactInfo.query(' declare namespace act="http://schemas.microsoft.com/sqlserver/2004/07/adve nture-works/ContactTypes"; declare namespace aci="http://schemas.microsoft.com/sqlserver/2004/07/adve nture-works/ContactInfo"; for $a in /aci:AdditionalContactInfo//act:telephoneNumber order by $a/act:number[1] descending

return $a ') As Result FROM Person.Person WHERE BusinessEntityID=291; Tenga en cuenta que el proceso de atomizacin (XQuery) recupera el valor atmico de los elementos <number> antes de pasarlo a order by. Puede escribir la expresin mediante la funcin data(), pero no es obligatorio. order by data($a/act:number[1]) descending El resultado es el siguiente: <act:telephoneNumber xmlns:act="http://schemas.microsoft.com/sqlserver/2004/0 7/adventure-works/ContactTypes"> <act:number>333-333-3334</act:number> </act:telephoneNumber> <act:telephoneNumber xmlns:act="http://schemas.microsoft.com/sqlserver/2004/0 7/adventure-works/ContactTypes"> <act:number>333-333-3333</act:number> </act:telephoneNumber> En lugar de declarar los espacios de nombres en el prlogo de la consulta, puede declararlos mediante el uso de WITH XMLNAMESPACES. WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTyp es' AS act, 'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInf o' AS aci) SELECT AdditionalContactInfo.query(' for $a in /aci:AdditionalContactInfo//act:telephoneNumber order by $a/act:number[1] descending return $a ') As Result FROM Person.Person WHERE BusinessEntityID=291; Tambin puede ordenar por valor de atributo. Por ejemplo, la consulta siguiente recupera los elementos <Location> recin creados que tienen los atributos LocationID y LaborHours ordenados por el atributo LaborHours en orden descendente. Como resultado, se devolvern primero las ubicaciones de centro de trabajo que tengan el mximo de horas de trabajo (LaborHours). SELECT Instructions.query(' declare namespace AWMI="http://schemas.microsoft.com/sqlserver/2004/07/a dventure-works/ProductModelManuInstructions"; for $WC in /AWMI:root/AWMI:Location order by $WC/@LaborHours descending return <Location> { $WC/@LocationID } { $WC/@LaborHours } </Location> ') as Result

FROM Production.ProductModel WHERE ProductModelID=7; El resultado es el siguiente: <Location <Location <Location <Location <Location <Location LocationID="60" LocationID="50" LocationID="10" LocationID="20" LocationID="30" LocationID="45" LaborHours="4"/> LaborHours="3"/> LaborHours="2.5"/> LaborHours="1.75"/> LaborHours="1"/> LaborHours=".5"/>

En la consulta siguiente, se ordenan los resultados por nombre de elemento. La consulta recupera las especificaciones de un producto determinado del catlogo de productos. Las especificaciones son los elementos secundarios del elemento < Specifications>. SELECT CatalogDescription.query(' declare namespace pd="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductMo delDescription"; for $a in /pd:ProductDescription/pd:Specifications/* order by local-name($a) return $a ') as Result FROM Production.ProductModel where ProductModelID=19; Observe lo siguiente en la consulta anterior: La expresin /p1:ProductDescription/p1:Specifications/* devuelve los elementos secundarios de <Specifications>. La expresin order by (local-name($a)) ordena la secuencia por la parte local del nombre del elemento.

El resultado es el siguiente: <Color>Available in most colors</Color> <Material>Almuminum Alloy</Material> <ProductLine>Mountain bike</ProductLine> <RiderExperience>Advanced to Professional riders</RiderExperience> <Style>Unisex</Style> Los nodos en los que se devuelve la expresin de ordenacin vaca se ordenan al principio de la secuencia, tal como se muestra en el ejemplo siguiente: declare @x xml set @x='<root> <Person Name="A" /> <Person /> <Person Name="B" /> </root> ' select @x.query(' for $person in //Person order by $person/@Name

return ')

$person

El resultado es el siguiente: <Person /> <Person Name="A" /> <Person Name="B" /> Se pueden especificar varios criterios de ordenacin, tal como se muestra en el ejemplo siguiente. La consulta de este ejemplo ordena los elementos <Employee> en primer lugar por ttulo (Title) y luego por los valores del atributo de administrador (Administrator). declare @x xml set @x='<root> <Employee ID="10" Title="Teacher" Gender="M" <Employee ID="15" Title="Teacher" Gender="F" /> <Employee ID="5" Title="Teacher" Gender="M" <Employee ID="11" Title="Teacher" Gender="F" <Employee ID="8" Title="Administrator" Gender="M" <Employee ID="4" Title="Administrator" Gender="F" <Employee ID="3" Title="Teacher" Gender="F" <Employee ID="125" Title="Administrator" Gender="F" SELECT @x.query('for $e in /root/Employee order by $e/@Title ascending, $e/@Gender descending return $e ') El resultado es el siguiente: <Employee <Employee <Employee <Employee <Employee <Employee <Employee <Employee ID="8" Title="Administrator" Gender="M" /> ID="4" Title="Administrator" Gender="F" /> ID="125" Title="Administrator" Gender="F" /> ID="10" Title="Teacher" Gender="M" /> ID="5" Title="Teacher" Gender="M" /> ID="11" Title="Teacher" Gender="F" /> ID="15" Title="Teacher" Gender="F" /> ID="3" Title="Teacher" Gender="F" />

/> /> /> /> /> /> /></root>'