Expresiones SequenceType (XQuery)
En XQuery, un valor siempre es una secuencia. Se hace referencia a los tipos de valor como tipos de secuencia. Los tipos de secuencia se pueden utilizar en las expresiones XQuery instance of. La sintaxis SequenceType descrita en la especificación de XQuery se utiliza cuando se debe hacer referencia a un tipo de una expresión XQuery.
El nombre de tipo atómico también se puede utilizar en la expresión XQuery cast as. En SQL Server, se admiten parcialmente las expresiones XQuery instance of y cast as en SequenceTypes.
Operador instance of
El operador instance of se puede utilizar para determinar el tipo dinámico o de tiempo de ejecución del valor de la expresión especificada. Por ejemplo:
Expression instance of SequenceType[Occurrence indicator]
Tenga en cuenta que el operador instance of , Occurrence indicator, especifica la cardinalidad, el número de elementos de la secuencia resultante. Si no se especifica esto, se supone que la cardinalidad es 1. En SQL Server, sólo se admite el indicador de aparición del signo de interrogación (?). El indicador de repetición ? indica que Expression puede devolver cero o un elemento. Si se especifica el indicador de repetición ?, instance of devolverá True cuando el tipo Expression coincida con el valor SequenceType especificado, independientemente de si Expression devuelve un singleton o una secuencia vacía.
Si no se especifica el indicador de repetición ?, sequence of sólo devolverá True cuando el tipo Expression coincida con el valor de Type especificado y Expression devolverá un singleton.
Nota Los indicadores de repetición signo más (+) y asterisco (*) no se admiten en SQL Server.
En los ejemplos siguientes se ilustra el uso del operador XQuery instance of.
Ejemplo A
En el ejemplo siguiente se crea una variable de tipo xml y se especifica una consulta con la misma. La expresión de consulta especifica un operador instance of para determinar si el tipo dinámico del valor devuelto por el primer operando coincide con el tipo especificado en el segundo operando.
La consulta siguiente devuelve True, pues el valor 125 es una instancia del tipo especificado, xs:integer:
declare @x xml
set @x=''
select @x.query('125 instance of xs:integer')
go
La consulta siguiente devuelve True, pues el valor devuelto por la expresión, /a[1], del primer operando es un elemento:
declare @x xml
set @x='<a>1</a>'
select @x.query('/a[1] instance of element()')
go
De forma similar, instance of devuelve True en la consulta siguiente, porque el tipo de valor de la primera expresión es un atributo:
declare @x xml
set @x='<a attr1="x">1</a>'
select @x.query('/a[1]/@attr1 instance of attribute()')
go
En el ejemplo siguiente, la expresión, data(/a[1], devuelve un valor atómico con el tipo xdt:untypedAtomic. Por tanto, instance of devuelve True.
declare @x xml
set @x='<a>1</a>'
select @x.query('data(/a[1]) instance of xdt:untypedAtomic')
go
En la consulta siguiente, la expresión, data(/a[1]/@attrA, devuelve un valor atómico sin tipo. Por tanto, instance of devuelve True.
declare @x xml
set @x='<a attrA="X">1</a>'
select @x.query('data(/a[1]/@attrA) instance of xdt:untypedAtomic')
go
Ejemplo B
En este ejemplo, se consulta una columna con el tipo XML de la base de datos de ejemplo AdventureWorks2008R2. La colección de esquemas XML asociada con la columna que se consulta proporciona la información de escritura.
En la expresión, data() devuelve el valor con tipo del atributo ProductModelID cuyo tipo es xs:string de acuerdo con el esquema asociado con la columna. Por tanto, instance of devuelve True.
SELECT CatalogDescription.query('
declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
data(/PD:ProductDescription[1]/@ProductModelID) instance of xs:string
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19
Para obtener más información, consulte Comparación de XML con tipo y XML sin tipo. Para obtener información acerca de la colección de esquemas XML asociada con la columna CatalogDescription, vea Columna XML ProductModel.CatalogDescription.
Las consultas siguientes utilizan la expresión booleana instance of para determinar si el tipo del atributo LocationID es xs:integer:
SELECT Instructions.query('
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/AWMI:root[1]/AWMI:Location[1]/@LocationID instance of attribute(LocationID,xs:integer)
') as Result
FROM Production.ProductModel
WHERE ProductModelID=7
La consulta siguiente se especifica con la columna XML de tipo CatalogDescription. La colección de esquemas XML asociada con esta columna proporciona la información de escritura. Para obtener más información acerca de la colección de esquemas XML, vea Columna XML ProductModel.CatalogDescription.
La consulta utiliza la prueba element(ElementName, ElementType?) en la expresión instance of para comprobar que /PD:ProductDescription[1] devuelve un nodo de elemento con un nombre y tipo específicos.
SELECT CatalogDescription.query('
declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
/PD:ProductDescription[1] instance of element(PD:ProductDescription, PD:ProductDescription?)
') as Result
FROM Production.ProductModel
where ProductModelID=19
La consulta devuelve True.
Ejemplo C
Cuando se utilizan tipos de unión, la expresión instance of de SQL Server tiene una limitación: en concreto, cuando el tipo de un elemento o atributo es un tipo de unión, puede que instance of no determine el tipo exacto. Por tanto, una consulta devolverá False, a menos que los tipos atómicos utilizados en SequenceType sean los elementos principales máximos del tipo real de la expresión de la jerarquía simpleType. Es decir, los tipos atómicos especificados en SequenceType deben ser secundarios directos de anySimpleType. Para obtener información acerca de la jerarquía de tipos, vea Reglas de conversión de tipos en XQuery.
En la siguiente consulta de ejemplo se realiza lo siguiente:
Se crea una colección de esquemas XML con un tipo de unión, como un tipo entero o de cadena, definido en la misma.
Se declara una variable de tipo xml mediante la colección de esquemas XML.
Se asigna una instancia XML de ejemplo a la variable.
Se consulta la variable para ilustrar el comportamiento de instance of cuando se trata con un tipo de unión.
Ésta es la consulta:
CREATE XML SCHEMA COLLECTION MyTestSchema AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ns" xmlns:ns="http://ns">
<simpleType name="MyUnionType">
<union memberTypes="integer string"/>
</simpleType>
<element name="TestElement" type="ns:MyUnionType"/>
</schema>'
Go
La consulta siguiente devuelve False, pues el valor de SequenceType especificado en la expresión instance of no es el principal máximo del tipo real de la expresión especificada. Es decir, el valor de <TestElement> es de tipo entero. El principal máximo es xs:decimal. No obstante, no se especifica como el segundo operando del operador instance of.
SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns"
data(/ns:TestElement[1]) instance of xs:integer')
go
Puesto que el principal máximo de xs:integer es xs:decimal, la consulta devolverá True si se modifica la consulta y se especifica xs:decimal como SequenceType en la misma.
SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns"
data(/ns:TestElement[1]) instance of xs:decimal')
go
Ejemplo D
En este ejemplo, se crea en primer lugar una colección de esquemas XML y se utiliza para asignar un tipo a una variable xml. A continuación, se consulta la variable de tipo xml para ilustrar la funcionalidad de instance of.
La colección de esquemas XML siguiente define un tipo simple, myType, y un elemento, <root>, del tipo myType:
drop xml schema collection SC
go
CREATE XML SCHEMA COLLECTION SC AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="myNS" xmlns:ns="myNS"
xmlns:s="https://schemas.microsoft.com/sqlserver/2004/sqltypes">
<import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes"/>
<simpleType name="myType">
<restriction base="s:varchar">
<maxLength value="20"/>
</restriction>
</simpleType>
<element name="root" type="ns:myType"/>
</schema>'
Go
A continuación, se crea una variable de tipo xml y se consulta:
DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS";
data(/ns:root[1]) instance of ns:myType')
go
Puesto que el tipo myType procede por restricción de un tipo varchar definido en el esquema sqltypes, instance of también devolverá True.
DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS";
data(/ns:root[1]) instance of sqltypes:varchar?')
go
Ejemplo E
En el ejemplo siguiente, la expresión recupera uno de los valores del atributo IDREFS y utiliza instance of para determinar si el valor es del tipo IDREF. En el ejemplo se realizan las operaciones siguientes:
Se crea una colección de esquemas XML en la que el elemento <Customer> tiene un atributo OrderList de tipo IDREFS, y el elemento <Order> tiene un atributo OrderID de tipo ID.
Se crea una variable de tipo xml y se le asigna una instancia XML de ejemplo.
Se especifica una consulta con la variable. La expresión de consulta recupera el primer valor de Id. de orden del atributo OrderList de tipo IDRERS del primer <Customer>. El valor recuperado es de tipo IDREF. Por tanto, instance of devuelve True.
create xml schema collection SC as
'<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:Customers="Customers" targetNamespace="Customers">
<element name="Customers" type="Customers:CustomersType"/>
<complexType name="CustomersType">
<sequence>
<element name="Customer" type="Customers:CustomerType" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="OrderType">
<sequence minOccurs="0" maxOccurs="unbounded">
<choice>
<element name="OrderValue" type="integer" minOccurs="0" maxOccurs="unbounded"/>
</choice>
</sequence>
<attribute name="OrderID" type="ID" />
</complexType>
<complexType name="CustomerType">
<sequence minOccurs="0" maxOccurs="unbounded">
<choice>
<element name="spouse" type="string" minOccurs="0" maxOccurs="unbounded"/>
<element name="Order" type="Customers:OrderType" minOccurs="0" maxOccurs="unbounded"/>
</choice>
</sequence>
<attribute name="CustomerID" type="string" />
<attribute name="OrderList" type="IDREFS" />
</complexType>
</schema>'
go
declare @x xml(SC)
set @x='<CustOrders:Customers xmlns:CustOrders="Customers">
<Customer CustomerID="C1" OrderList="OrderA OrderB" >
<spouse>Jenny</spouse>
<Order OrderID="OrderA"><OrderValue>11</OrderValue></Order>
<Order OrderID="OrderB"><OrderValue>22</OrderValue></Order>
</Customer>
<Customer CustomerID="C2" OrderList="OrderC OrderD" >
<spouse>John</spouse>
<Order OrderID="OrderC"><OrderValue>33</OrderValue></Order>
<Order OrderID="OrderD"><OrderValue>44</OrderValue></Order>
</Customer>
<Customer CustomerID="C3" OrderList="OrderE OrderF" >
<spouse>Jane</spouse>
<Order OrderID="OrderE"><OrderValue>55</OrderValue></Order>
<Order OrderID="OrderF"><OrderValue>55</OrderValue></Order>
</Customer>
<Customer CustomerID="C4" OrderList="OrderG" >
<spouse>Tim</spouse>
<Order OrderID="OrderG"><OrderValue>66</OrderValue></Order>
</Customer>
<Customer CustomerID="C5" >
</Customer>
<Customer CustomerID="C6" >
</Customer>
<Customer CustomerID="C7" >
</Customer>
</CustOrders:Customers>'
select @x.query(' declare namespace CustOrders="Customers";
data(CustOrders:Customers/Customer[1]/@OrderList)[1] instance of xs:IDREF ? ') as XML_result
Limitaciones de la implementación
Éstas son las limitaciones:
No se admiten los tipos de secuencia schema-element() y schema-attribute() para la comparación con el operador instance of.
No se admiten las secuencias completas, como (1,2) instance of xs:integer*.
Cuando se utiliza una forma del tipo de secuencia element() que especifica un nombre de tipo, como element(ElementName, TypeName), el tipo debe ser completo con un signo de interrogación (?). Por ejemplo, element(Title, xs:string?) indica que puede que el elemento sea nulo. SQL Server no admite la detección en tiempo de ejecución de la propiedad xsi:nil mediante instance of.
Si el valor de Expression procede de un elemento o atributo del tipo unión, SQL Server sólo podrá identificar el tipo primitivo, no derivado, del que procede el tipo del valor. Por ejemplo, si se define <e1> para que tenga un tipo estático de (xs:integer | xs:string), el ejemplo siguiente devolverá False.
data(<e1>123</e1>) instance of xs:integer
Sin embargo, data(<e1>123</e1>) instance of xs:decimal devolverá True.
En el caso de los tipos de secuencia processing-instruction() y document-node(), sólo se admiten las formas sin argumentos. Por ejemplo, se admite processing-instruction() pero no processing-instruction('abc').
Operador cast as
Se puede utilizar la expresión cast as para convertir un valor en un tipo de datos específico. Por ejemplo:
Expression cast as AtomicType?
En SQL Server, el signo de interrogación (?) se requiere después del AtomicType. Por ejemplo, tal como se muestra en la consulta siguiente, "2" cast as xs:integer? convierte el valor de cadena en un entero:
declare @x xml
set @x=''
select @x.query('"2" cast as xs:integer?')
En la consulta siguiente, data() devuelve el valor con tipo del atributo ProductModelID, un tipo de cadena. El operador cast as convierte el valor en xs:integer.
WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD)
SELECT CatalogDescription.query('
data(/PD:ProductDescription[1]/@ProductModelID) cast as xs:integer?
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19
Esta consulta no requiere el uso explícito de data(). La expresión cast as realiza una atomización implícita en la expresión de entrada.
Funciones de constructor
Se pueden utilizar las funciones de constructor de tipo atómico. Por ejemplo, en lugar de utilizar el operador cast as, "2" cast as xs:integer?, puede utilizar la función de constructor xs:integer(), como en el ejemplo siguiente:
declare @x xml
set @x=''
select @x.query('xs:integer("2")')
En el ejemplo siguiente se devuelve un valor xs:date equivalente a 2000-01-01Z.
declare @x xml
set @x=''
select @x.query('xs:date("2000-01-01Z")')
También se pueden utilizar constructores para los tipos atómicos definidos por el usuario. Por ejemplo, si la colección de esquemas XML asociada con el tipo de datos XML define un tipo simple, se puede utilizar un constructor myType() para devolver un valor de ese tipo.
Limitaciones de la implementación
No se admiten las expresiones XQuery typeswitch, castable y treat.
cast as requiere un signo de interrogación (?) después del tipo atómico.
No se admite xs:QName como tipo para la conversión. En su lugar, utilice expanded-QName.
xs:date, xs:time y xs:datetime requieren una zona horaria, que se indica mediante una Z.
La consulta siguiente provocará un error, pues no se ha especificado ninguna zona horaria.
DECLARE @var XML SET @var = '' SELECT @var.query(' <a>{xs:date("2002-05-25")}</a>') go
Si se agrega el indicador de zona horaria Z al valor, la consulta funcionará.
DECLARE @var XML SET @var = '' SELECT @var.query(' <a>{xs:date("2002-05-25Z")}</a>') go
El resultado es el siguiente:
<a>2002-05-25Z</a>