Directrices para utilizar los métodos del tipo de datos xml
En este tema se describen instrucciones para utilizar los métodos de tipo de datos xml.
La instrucción PRINT
Los métodos del tipo de datos xml no se pueden utilizar en la instrucción PRINT, como se muestra en el ejemplo siguiente. Los métodos del tipo de datos xml se tratan como subconsultas y éstas no están permitidas en la instrucción PRINT. Como resultado, el ejemplo siguiente devuelve un error:
DECLARE @x xml
SET @x = '<root>Hello</root>'
PRINT @x.value('/root[1]', 'varchar(20)') -- will not work because this is treated as a subquery (select top 1 col from table)
Una solución es asignar primero el resultado del método value() a una variable de tipo xml y, después, especificar la variable en la consulta.
DECLARE @x xml
DECLARE @c varchar(max)
SET @x = '<root>Hello</root>'
SET @c = @x.value('/root[1]', 'varchar(11)')
PRINT @c
La cláusula GROUP BY
Los métodos del tipo de datos xml se tratan internamente como subconsultas. Como GROUP BY requiere un valor escalar y no permite agregados ni subconsultas, no se pueden especificar los métodos del tipo de datos xml en la cláusula GROUP BY. Una solución es llamar a una función definida por el usuario que utilice métodos XML en su interior.
La notificación de errores
Al informar de errores, los métodos del tipo de datos xml generan un único error con el formato siguiente:
Msg errorNumber, Level levelNumber, State stateNumber:
XQuery [database.table.method]: description_of_error
Por ejemplo:
Msg 2396, Level 16, State 1:
XQuery [xmldb_test.xmlcol.query()]: Attribute may not appear outside of an element
Comprobaciones de singleton
Los pasos de ubicación, los parámetros de funciones y los operadores que requieren singleton devolverán un error si el compilador no puede determinar si se garantiza un singleton en tiempo de ejecución. Este problema es frecuente con datos sin tipo. Por ejemplo, la búsqueda de un atributo requiere un elemento primario singleton. Es suficiente con un ordinal que seleccione un solo nodo primario. Es posible que la evaluación de una combinación node()-value() para extraer valores de atributos no requiera la especificación del ordinal. Esto se muestra en el ejemplo siguiente.
Ejemplo: singleton conocido
En este ejemplo, el método nodes() genera una fila distinta para cada elemento <book>. El método value() que se evalúa en un nodo <book> extrae el valor de @genre y, siendo un atributo, es un singleton.
SELECT nref.value('@genre', 'varchar(max)') LastName
FROM T CROSS APPLY xCol.nodes('//book') AS R(nref)
El esquema XML se utiliza para comprobar el tipo del XML con tipo. Si se especifica un nodo como singleton en el esquema XML, el compilador usa esa información y no se produce ningún error. En caso contrario, se necesita un ordinal que seleccione un solo nodo. En particular, el uso de ejes descendant-or-self (//), como en /book//title, pierde inferencia de cardinalidad de singleton para el elemento <title>, incluso si el esquema XML especifica que sea así. Por tanto, se debe volver a escribir como (/book//title)[1].
Es importante ser consciente de la diferencia entre //first-name[1] y (//first-name)[1] para la comprobación de tipos. La primera expresión devuelve una secuencia de nodos <first-name> en la que cada nodo es el que está más a la izquierda entre los de su mismo nivel. La última expresión devuelve el primer nodo singleton <first-name> por orden de los documentos en la instancia XML.
Ejemplo: utilizar value()
La siguiente consulta en una columna XML sin tipo da como resultado un error de compilación estático. Esto se debe a que value() espera un nodo singleton como primer argumento y el compilador no puede determinar si solo va a aparecer un nodo <last-name> en tiempo de ejecución:
SELECT xCol.value('//author/last-name', 'nvarchar(50)') LastName
FROM T
A continuación, se ofrece una solución que debe contemplar:
SELECT xCol.value('//author/last-name[1]', 'nvarchar(50)') LastName
FROM T
No obstante, esta solución no resuelve el error, ya que pueden aparecer varios nodos <author> en cada instancia XML. Resulta útil volver a escribir lo siguiente:
SELECT xCol.value('(//author/last-name/text())[1]', 'nvarchar(50)') LastName
FROM T
Esta consulta devuelve el valor del primer elemento <last-name> de cada instancia XML.