Règles de conversion de types dans XQuery
S'applique à : SQL Server
Le diagramme des spécifications suivant, retraçant les fonctions et les opérateurs XQuery 1.0 et XPath 2.0 définis par le W3C, illustre les types de données intégrés. Parmi ces types, on retrouve les types intégrés de primitives et de dérivées.
Cette rubrique décrit donc les règles de conversion de types applicables suivant une des deux méthodes suivantes :
Cast explicite que vous effectuez à l’aide de la conversion en tant que ou des fonctions de constructeur de type (par exemple,
xs:integer("5")
).la conversion implicite qui a lieu pendant la promotion de type à un rang supérieur.
Conversion explicite
Le tableau suivant présente la conversion de types autorisée entre les différents types de primitives intégrés.
Un type de primitive intégré peut se convertir en un autre type de primitive intégré en respectant les règles en vigueur sur les données de la table.
Un type de primitive peut également se convertir en tout autre type dérivé de ce type de primitive. Par exemple, vous pouvez effectuer un cast de xs :decimal en xs :integer, ou de xs :decimal à xs :long.
Un type dérivé peut être converti en tout autre type dont il constitue l'ancêtre dans la hiérarchie des types, et ce jusqu'à son type de primitive de base intégré. Par exemple, vous pouvez effectuer un cast de xs :token en xs :normalizedString ou en xs :string.
Un type dérivé peut également être converti en type de primitive si l'ancêtre de sa primitive peut aussi être converti dans le type cible. Par exemple, vous pouvez convertir xs :integer, un type dérivé, en xs :string, type primitif, car xs :decimal, xs :integer’s primitive ancêtre, peut être converti en xs :string.
Un type dérivé peut également être converti en autre type dérivé si l'ancêtre de la primitive du type source peut aussi être converti en ancêtre de primitive du type cible. Par exemple, vous pouvez effectuer un cast de xs :integer en xs :token, car vous pouvez effectuer un cast de xs :decimal en xs :string.
Les règles pour la conversion de types définis par l'utilisateur en types intégrés revient au même que pour la conversion de types intégrés. Par exemple, vous pouvez définir un type myInteger dérivé du type xs :integer . Ensuite, myInteger peut être converti en xs :token, car xs :decimal peut être converti en xs :string.
Les types de conversion suivants ne sont pas pris en charge :
La conversion mettant en œuvre les types de liste n'est pas autorisée. Cela inclut les types de liste définis par l’utilisateur et les types de liste intégrés tels que xs :IDREFS, xs :ENTITIES et xs :NMTOKENS.
La conversion vers ou à partir de xs :QName n’est pas prise en charge.
xs :NOTATION et sous-types de durée , xdt :yearMonthDuration et xdt :dayTimeDuration, ne sont pas pris en charge. C'est pour cela que la conversion mettant en œuvre ces types n'est pas prise en charge.
Les exemples suivants illustrent la conversion explicite de types.
Exemple A
L'exemple suivant interroge une variable de type xml. Elle renvoie ainsi une séquence de valeurs de type simple typé en xs:string.
declare @x xml
set @x = '<e>1</e><e>2</e>'
select @x.query('/e[1] cast as xs:string?')
go
Exemple B
L'exemple suivant interroge une variable xml typé. Nous procédons ainsi dans un premier temps à la création d'une collection de schémas XML. Nous utilisons ensuite cette collection afin de créer à son tour une variable XML typé. Le schéma fournit alors les informations de typage pour l'instance XML affectée à la variable. Des requêtes sont ensuite lancées sur la variable.
create xml schema collection myCollection as N'
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="A" type="xs:string"/>
<xs:element name="B" type="xs:string"/>
<xs:element name="C" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>'
go
La requête suivante retourne une erreur statique, car vous ne savez pas combien d’éléments de niveau <root
> supérieur se trouvent dans l’instance de document.
declare @x xml(myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</baz></C>'
select @x.query('/root/A cast as xs:string?')
go
En spécifiant un élément singleton <root
> dans l’expression, la requête réussit. Elle renvoie ainsi une séquence de valeurs de type simple typé en xs:string.
declare @x xml(myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</C></root>'
select @x.query('/root[1]/A cast as xs:string?')
go
Dans l'exemple suivant, la variable de type xml inclut un mot clé document précisant la collection de schémas XML. Cela indique que l'instance XML doit être un document ne possédant qu'un seul élément de premier niveau. Si vous créez deux <root
> éléments dans l’instance XML, il retourne une erreur.
declare @x xml(document myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</C></root>'
go
Vous pouvez modifier l'instance afin de n'inclure qu'un seul élément de premier niveau et faire fonctionner ainsi la requête. Elle renvoie donc une séquence de valeurs de type simple typé en xs:string.
declare @x xml(document myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>'
select @x.query('/root/A cast as xs:string?')
go
Conversion implicite
La conversion implicite n'est autorisée que pour les types numériques et les types atomiques non typés. Par exemple, la fonction min() suivante retourne le minimum des deux valeurs :
min(xs:integer("1"), xs:double("1.1"))
Dans cet exemple, les deux valeurs passées à la fonction XQuery min() sont de différents types. Par conséquent, la conversion implicite est effectuée où le type entier est promu en double et les deux valeurs doubles sont comparées.
La promotion de type telle qu'elle est décrite dans cet exemple suit les règles suivantes :
Un type numérique dérivé peut être promu en son type de base. Par exemple, l’entier peut être promu en décimal.
Une décimale peut être promue en float, et un float peut être promu à double.
La conversion implicite n'étant autorisée que pour les types numériques, ce qui suit n'est pas possible :
La conversion implicite mettant en œuvre les types de chaîne (string) n'est pas autorisée. Par exemple, si deux types de chaînes sont attendus et que vous passez une chaîne et un jeton, aucun cast implicite ne se produit et une erreur est retournée.
La conversion implicite des types numériques en types de chaînes n'est pas non plus autorisée. Ainsi, si vous transmettez une valeur de type integer à une fonction s'attendant à un paramètre de type string (chaîne), là encore la conversion implicite ne peut pas se produire et entraîne une erreur.
Conversion de valeurs
Lors de la conversion d'un type vers un autre, les valeurs sont en fait transformées de l'espace de valeurs du type source à celui du type cible. Par exemple, la conversion de xs:decimal en xs:double transforme la valeur décimale en valeur double.
Voici quelques-unes des règles qui s'appliquent lors de la transformation.
Conversion d'une valeur de type string ou de type untypedAtomic
Une valeur convertie en un type string (chaîne) ou untypedAtomic (atomique non typé) est transformée comme si elle faisait l'objet d'une validation suivant les règles du type cible. Cela inclut les règles éventuelles de traitement des modèles et des espaces. Par exemple, l'instruction suivante fonctionne et génère ainsi une valeur de type double (1.1e0) :
xs:double("1.1")
Lors de la conversion vers des types binaires tels que xs:base64Binary ou xs:hexBinary à partir d'un type string (chaîne) ou untypedAtomic (atomique non typé), la valeur d'entrée doit être encodée respectivement au format base64 ou HEX.
Conversion d'une valeur en valeur de type string ou untypedAtomic
La conversion vers un type string (chaîne) ou untypedAtomic (atomique non typé) transforme la valeur en sa représentation lexicale canonique XQuery. Plus précisément, on peut dire qu'une valeur ayant répondu à un modèle précis ou à une autre contrainte lors de sa saisie pourrait ne pas être représentée en fonction de ladite contrainte. Pour informer les utilisateurs de ce problème, SQL Server signale les types où la contrainte de type peut être un problème en fournissant un avertissement lorsque ces types sont chargés dans la collection de schémas.
Lors de la conversion d'une valeur de type xs:float ou xs:double, ou encore de l'un de leurs sous-types, en une valeur de type string ou untypedAtomic, ladite valeur est alors représentée sous sa forme scientifique. Cette opération n'est effectuée que si la valeur absolue de la donnée est inférieure à 1,0E-6 ou supérieure ou égale à 1,0E6. Dans ce cas, 0 est sérialisé sous sa forme scientifique de 0,0E0.
Par exemple, xs:string(1.11e1)
renvoie la valeur de type chaîne "11.1"
, alors que xs:string(-0.00000000002e0)
renvoie la valeur de type chaîne "-2.0E-11"
.
Lors de la conversion de types binaires tels que xs:base64Binary ou xs:hexBinary en un type string (chaîne) ou untypedAtomic (atomique non typé), les valeurs binaires sont alors respectivement encodées au format base64 ou HEX.
Conversion d'une valeur en valeur de type numérique
Lors de la conversion d'une valeur d'un des types numériques en une valeur d'un autre type numérique, la valeur est alors mappée d'un espace de valeurs à l'autre sans passer par la sérialisation par chaîne. Si elle ne satisfait pas la contrainte relative au type cible, les règles suivantes s'appliquent alors :
Si la valeur source est déjà de type numérique et le type cible est xs:float ou un de ses sous-types acceptant les valeurs -INF ou INF, et si la conversion de la valeur numérique source provoque un dépassement de capacité, la valeur est alors mappée à INF si elle est positive ou à -INF si elle est négative. Si le type cible n'accepte pas ces valeurs INF ou -INF entraînant ainsi un dépassement de capacité, la conversion échoue et le résultat (dans le cas de cette version de SQL Server) correspond ainsi à la séquence vide.
Si la valeur source est déjà de type numérique et le type cible est un type numérique acceptant les valeurs 0, -0e0 ou 0e0 dans sa plage de valeurs, si la conversion de la valeur numérique source provoque un dépassement de capacité, la valeur est mappée selon les cas suivants :
La valeur est mappée à 0 pour un type cible décimal.
La valeur est mappée à -0e0 si la valeur correspond à un dépassement de capacité négatif.
La valeur est mappée sur 0e0 si la valeur correspond à un dépassement de capacité positif pour un type float ou double.
Si le type cible n'inclut pas le zéro dans son espace de valeurs, la conversion échoue et le résultat est alors la séquence vide.
Remarque : il se peut que la conversion d'une valeur en un type à virgule flottante binaire, tel que xs:float, xs:double ou un de leurs sous-types, entraîne une perte de précision.
Limites de mise en œuvre
Les limitations suivantes s'appliquent :
La valeur à virgule flottante NaN n'est pas prise en charge.
Les valeurs convertibles sont limitées par les restrictions d'implémentation des types de cibles. Par exemple, vous ne pouvez pas caster une chaîne de date avec une année négative en xs :date. De telles conversions génèreront la séquence vide si la valeur est fournie au moment de l'exécution (au lieu de déclencher une erreur d'exécution).