Download - SQL con XML
ESCUELA POLITÉCNICA NACIONAL
FACULTAD DE INGENIERÍA DE SISTEMAS
BASE DE DATOS
Integrantes
Edison Quisiguiña
David Montúfar
Pablo Guachamín
Roberto Lema
Fabián Vásquez
INTRODUCCION A XML
Lenguajes de Marcas
En los años 60, IBM intentó resolver sus problemas asociados al tratamiento de documentos en diferentes
plataformas a través de GML (Generalized markup Language).
El principal problema era que cada aplicación utilizaba sus propias marcas para describir los diferentes
elementos. Las marcas son códigos que indican a un programa cómo debe tratar su contenido y así, si se desea
que un texto aparezca con un formato determinado, dicho texto debe ir delimitado por la correspondiente
marca que indique como debe ser mostrado en pantalla o impreso. Y lo mismo ocurre con todas las demás
características de cualquier texto. Ejemplos pueden tenerlos en mente los usuarios de WordPerfect.
Conociendo este sistema y conociendo a la perfección el sistema de marcas de cada aplicación sería posible
pasar información de un sistema a otro sin necesidad de perder el formato indicado. La forma que IBM creó
para solventar esto se basaba en tratar las marcas como texto accesible desde cualquier sistema, texto plano,
código ASCII. Y la norma se denominó GML (General Modeling Language).
Más tarde GML pasó a manos de ISO y se convirtio en SGML ( ISO 8879), Standart Generalized Markup
Language. Esta norma es la que se aplica desde entonces a todos los lenguajes de marcas, cuyos ejemplos más
conocidos son el HTML y el RTF.
Los lenguajes de marcas no son equivalentes a los lenguajes de programación aunque se definan igualmente
como "lenguajes". Son sistemas complejos de descripción de información, normalmente documentos, que si se
ajustan a SGML, se pueden controlar desde cualquier editor ASCII. Las marcas más utilizadas suelen describirse
por textos descriptivos encerrados entre signos de "menor" (<) y "mayor" (>), siendo lo más usual que existan
una marca de principio y otra de final.
Se puede decir que existen tres utilizaciones básicas de los lenguajes de marcas: los que sirven principalmente
para describir su contenido, los que sirven más que nada para definir su formato y los que realizan las dos
funciones indistintamente. Las aplicaciones de bases de datos son buenas referencias del primer sistema, los
programas de tratamiento de textos son ejemplos típicos del segundo tipo, y aunque no lo parezca, el HTML es
la muestra más conocida del tercer modelo.
¿Qué es XML?
XML, es el estandar de Extensible Markup Language. XML no es más que un conjunto de reglas para definir
etiquetas semánticas que nos organizan un documento en diferentes partes. XML es un metalenguaje que
define la sintaxis utilizada para definir otros lenguajes de etiquetas estructurados.
En primer lugar para entenderlo bien hay que olvidarse un poco, sólo un poco de HTML. En teoría HTML es un
subconjunto de XML especializado en presentación de documentos para la Web, mientras que XML es un
subconjunto de SGML especializado en la gestión de información para la Web. En la práctica XML contiene a
HTML aunque no en su totalidad. La definición de HTML contenido totalmente dentro de XML y por lo tanto
que cumple a rajatabla la especificación SGML es XHTML (Extensible, Hypertext Markup Language).
Desde su creación, XML ha despertado encontradas pasiones, y como para cualquier tema en Internet, hay
gente que desde el principio se deja iluminar por sus expectativas, mientras otras muchas lo han ignorado.
CREAR VARIABLES Y COLUMNAS DEL TIPO DE DATOS XML
El tipo de datos xml es un tipo de datos integrado de SQL Server y es similar a otros tipos integrados como int
y varchar. Al igual que ocurre con otros tipos integrados, se puede utilizar el tipo de datos xml como un tipo de
columna al crear una tabla como un tipo de variable, un tipo de parámetro, un tipo de valor devuelto por una
función o en CAST y CONVERT.
Crear columnas y variables
Para crear una columna de tipo XML como parte de una tabla utilizaremos la instrucción CREATE TABLE.
CREATE TABLE T1(Col1 int primary key, Col2 xml)
La declaración de una variable de tipo XML se realiza mediante la instrucción DECLARE, especificando
una colección de esquemas XML.
DECLARE @x xml (Sales.StoreSurveySchemaCollection)
Para pasar un parámetro de tipo xml a un procedimiento almacenado, se emplea la instrucción CREATE
PROCEDURE.
CREATE PROCEDURE SampleProc(@XmlDoc xml) AS ...
Asignar valores predeterminados
En una tabla, puede asignar una instancia XML predeterminada a una columna de tipo xml. Puede proporcionar
el XML predeterminado de una de estas dos maneras: con una constante XML o con una conversión explícita al
tipo xml.
Para proporcionar el XML predeterminado como una constante XML se lo debe realizar como se
muestra a continuación. Observe que la cadena se convierte implícitamente al tipo xml.
CREATE TABLE T (XmlColumn xml default N'<element1/><element2/>')
Para proporcionar el XML predeterminado mediante una operación de conversión (CAST) explícita a xml.
Por ejemplo:
CREATE TABLE T (XmlColumn xml
default CAST(N'<element1/><element2/>' AS xml))
SQL Server también admite restricciones NULL y NOT NULL en columnas de tipo xml. Por ejemplo: CREATE TABLE T (XmlColumn xml NOT NULL)
Especificar restricciones
Al crear columnas de tipo xml, puede definir restricciones de nivel de columna o de nivel de tabla. Las
restricciones se emplean en estas situaciones:
Las reglas de su empresa no se pueden expresar en esquemas XML. Por ejemplo, la dirección de entrega
de una floristería debe estar a menos de 75 kilómetros de su ubicación. Esto se puede escribir como una
restricción en la columna XML. La restricción puede afectar a métodos de tipo de datos xml.
La restricción afecta a otras columnas XML o no XML de la tabla. Un ejemplo puede ser obligar a que el
Id. de un cliente (/Customer/@CustId) existente en una instancia XML coincida con el valor de una
columna relacional CustomerID.
Puede especificar restricciones para columnas de tipo de datos xml con o sin tipo. Sin embargo, no puede usar
los métodos de tipo de datos XML al especificar restricciones. También debe tener en cuenta que el tipo de
datos xml no admite las restricciones de columna y de tabla siguientes:
PRIMARY KEY / FOREIGN KEY
UNIQUE
COLLATE
XML proporciona su propia codificación. Las intercalaciones sólo se aplican a los tipos de cadena. El tipo
de datos xml no es un tipo de cadena. No obstante, tiene una representación de cadena y permite la
conversión a tipos de datos de cadena y desde tipos de datos de cadena.
RULE
Una alternativa al uso de restricciones consiste en crear una función de contenedor definida por el usuario para
ajustar el método de tipo de datos xml y especificar una función definida por el usuario en la restricción CHECK,
como se muestra a continuación.
En el siguiente ejemplo, la restricción de Col2 especifica que cada instancia XML almacenada en esta columna
debe tener un elemento <ProductDescription> con un atributo ProductID. Esta restricción se exige mediante la
siguiente función definida por el usuario:
CREATE FUNCTION my_udf(@var xml) returns bit
AS BEGIN
RETURN @var.exist('/ProductDescription/@ProductID')
END
GO
Observe que el método exist() del tipo de datos xml devuelve 1 si el elemento <ProductDescription> de la
instancia contiene el atributo ProductID. De lo contrario, devuelve 0.
En este momento, puede crear una tabla con una restricción de columna del modo siguiente:
CREATE TABLE T (
Col1 int primary key,
Col2 xml check(dbo.my_udf(Col2)=1))
GO
La inserción siguiente se realiza correctamente:
INSERT INTO T values(1,'<ProductDescription ProductID="1" />')
La inserción siguiente no se realiza correctamente a causa de la restricción:
INSERT INTO T values(1,'<Product />')
COMPARACIÓN DE XML CON TIPO Y XML SIN TIPO
Se pueden crear variables, parámetros y columnas del tipo de datos xml. Opcionalmente, se puede asociar una
colección de esquemas XML a una variable, a un parámetro o a una columna de tipo xml. En este caso, se
dice que la instancia del tipo de datos xml es una instancia con tipo. En los demás casos, se dice que la instancia
XML es una instancia sin tipo.
XML correcto y tipo de datos XML
El tipo de datos xml implementa el tipo de datos xml del estándar ISO. Por lo tanto, puede almacenar
documentos XML versión 1.0 correctos, así como los denominados fragmentos de contenido XML con nodos de
texto y un número arbitrario de elementos de nivel superior en una columna XML sin tipo. El sistema comprueba
que todos los datos tienen un formato correcto, no requiere que la columna esté enlazada a esquemas XML y
rechaza los datos que no tienen un formato correcto en sentido amplio. Esto también se cumple para
parámetros y variables XML sin tipo.
Esquemas XML
Un esquema XML proporciona lo siguiente:
Restricciones de validación. Siempre que se asigna o modifica una instancia XML con tipo, SQL Server
valida la instancia.
Información sobre el tipo de datos. Los esquemas proporcionan información sobre los tipos de
atributos y elementos de la instancia de tipo de datos xml. La información de tipo proporciona una
semántica operacional más precisa para los valores contenidos en la instancia que es posible con xml
sin tipo. Por ejemplo, se pueden realizar operaciones aritméticas con decimales en un valor decimal,
pero no en un valor de cadena. Por este motivo, el almacenamiento de XML con tipo puede ser mucho
más compacto que el de XML sin tipo.
Elegir XML con tipo o sin tipo
El tipo de datos xml sin tipo se emplea en las siguientes situaciones:
No tiene un esquema para los datos XML.
Tiene esquemas pero no desea que el servidor valide los datos. Esto a veces ocurre cuando una
aplicación realiza la validación en el cliente antes de almacenar los datos en el servidor, almacena
temporalmente datos XML que no son válidos según el esquema, o usa componentes del esquema que
no son compatibles con el servidor.
El tipo de datos xml con tipo se emplea en las siguientes situaciones:
Tiene esquemas para los datos XML y desea que el servidor valide estos datos según los esquemas XML.
Desea aprovechar las optimizaciones del almacenamiento y de las consultas en función de la
información del tipo.
Desea aprovechar mejor la información del tipo durante la compilación de las consultas.
Columnas, parámetros y variables XML con tipo pueden almacenar documentos o contenido XML. No obstante,
hay que especificar con un indicador si se va a almacenar un documento o contenido en el momento de la
declaración. Además, hay que proporcionar la colección de esquemas XML. Especifique DOCUMENT si cada
instancia XML tiene exactamente un elemento de nivel superior. En caso contrario, use CONTENT. El compilador
de consultas usa el indicador DOCUMENT en comprobaciones de tipo durante la compilación de consultas para
inferir elementos singleton de nivel superior.
Crear XML con tipo
Para poder crear variables, parámetros o columnas xml con tipo, primero es necesario registrar la colección de
esquemas XML mediante CREATE XML SCHEMA COLLECTION (Transact-SQL). Después, se puede asociar la
colección de esquemas XML a variables, parámetros o columnas del tipo de datos xml.
En los ejemplos siguientes se usa una convención de nomenclatura de dos partes para especificar el nombre de
la colección de esquemas XML. La primera parte corresponde al nombre de esquema de AdventureWorks y la
segunda corresponde al nombre de la colección de esquemas XML.
Ejemplo: Asociar una colección de esquemas con una variable de tipo XML
En el ejemplo siguiente se crea una variable de tipo xml y se le asocia una colección de esquemas. La colección
de esquemas especificada en el ejemplo ya se ha importado a la base de datos AdventureWorks. DECLARE @x xml (Production.ProductDescriptionSchemaCollection)
Ejemplo: Especificar un esquema para una columna de tipo XML
En el ejemplo siguiente se crea una tabla con una columna de tipo xml y se especifica un esquema para la
columna: CREATE TABLE T1(
Col1 int,
Col2 xml (Production.ProductDescriptionSchemaCollection))
Ejemplo: Pasar un parámetro de tipo XML a un procedimiento almacenado
En el ejemplo siguiente se pasa un parámetro de tipo xml a un procedimiento almacenado y se especifica un
esquema para la variable: CREATE PROCEDURE SampleProc
@ProdDescription xml (Production.ProductDescriptionSchemaCollection)
AS
Tenga en cuenta lo siguiente sobre la colección de esquemas XML:
Una colección de esquemas XML sólo está disponible en la base de datos en la que se ha registrado
mediante CREATE XML SCHEMA COLLECTION.
Si se realiza la conversión de una cadena a un tipo de datos xml con tipo, el análisis también realiza la
validación y la conversión de tipos, de acuerdo con los espacios de nombres de los esquemas XML de la
colección especificada.
Es posible convertir un tipo de datos xml con tipo en un tipo de datos xml sin tipo, y viceversa.
Para obtener más información sobre otras maneras de generar XML en SQL Server, vea Generar instancias XML.
Una vez generado el XML, se puede asignar a una variable del tipo de datos xml o se puede almacenar en
columnas de tipo xml para su posterior procesamiento.
En la jerarquía de tipos de datos, el tipo de datos xml aparece por debajo de sql_variant y los tipos definidos
por el usuario, pero por encima de los tipos integrados.
Ejemplo: Especificar aspectos para restringir una columna XML con tipo
En las columnas xml con tipo se puede restringir la columna para permitir que sólo se almacene en ella un único
elemento de nivel superior para cada instancia. Para ello, se especifica el aspecto opcional DOCUMENT cuando
se crea una tabla, como se muestra en el ejemplo siguiente: CREATE TABLE T(Col1 xml
(DOCUMENT Production.ProductDescriptionSchemaCollection))
GO
DROP TABLE T
GO
De manera predeterminada, las instancias se almacenan en la columna xml con tipo como contenido XML y no
como documentos XML. Esto permite lo siguiente:
Cero o varios elementos de nivel superior
Nodos de texto en elementos de nivel superior
Este comportamiento también se puede especificar explícitamente, agregando el aspecto CONTENT, tal y como
se muestra en el ejemplo siguiente: CREATE TABLE T(Col1 xml(CONTENT Production.ProductDescriptionSchemaCollection))
GO -- Default
Tenga en cuenta que puede especificar los aspectos de DOCUMENT/CONTENT opcionales en cualquier lugar
donde defina un tipo el xml (XML con tipo). Por ejemplo, cuando se crea una variable xml con tipo, se puede
agregar el aspecto DOCUMENT/CONTENT, como se muestra a continuación: declare @x xml (DOCUMENT Production.ProductDescriptionSchemaCollection)
Definición de tipo de documento (DTD)
Las columnas de tipo de datos xml, las variables y los parámetros pueden obtener tipos utilizando un esquema
XML, pero no mediante DTD. Sin embargo, se puede usar DTD en línea para XML con o sin tipo, para suministrar
valores predeterminados y reemplazar referencias a entidades por su forma expandida.
Puede convertir las DTD en documentos de esquemas XML mediante herramientas de otros fabricantes y cargar
los esquemas XML en la base de datos.
Actualizar XML con tipo de SQL Server 2005 a SQL Server 2008
SQL Server 2008 ha realizado varias extensiones a la compatibilidad con esquemas XML, incluyendo la
compatibilidad para la validación lax, el control mejorado de xs:date, xs:time y datos de instancia xs:dateTime,
y compatibilidad agregada para tipos de lista y tipos de unión. En la mayoría de los casos, los cambios no
afectan a la experiencia de actualización. Sin embargo si usa una colección de esquemas XML en SQL Server
2005 que permitia valores del tipo xs:date, xs:time o xs:dateTime (o cualquier subtipo), los pasos de
actualización siguientes se producen al asociar la base de datos de SQL Server 2005 a SQL Server 2008:
1. Para cada columna XML, que se escribe con una Colección de esquemas XML que contiene elementos o
atributos escritos como xs:anyType, xs:anySimpleType, xs:date o cualquiera de sus subtipos, xs:time
o cualquier subtipo, o xs:dateTime o cualquiera de sus subtipos ,o son tipos de unión o de lista que
contienen cualquiera de estos tipos, se produce lo siguiente:
a) Se deshabilitarán todos los índices XML de la columna.
b) Todos los valores de SQL Server 2005 continuarán representándose en la zona horaria Z porque
se han normalizado a dicha zona horaria.
c) Cualquier valor xs:date o xs:dateTime que sea menor que el 1 de enero del año 1 llevará a un
error en tiempo de ejecución cuando el índice se regenere o se ejecute una XQuery o
instrucciones XML-DML frente al tipo de datos XML que contiene dicho valor.
2. Cualquier año negativo en los aspectos o valores predeterminados de xs:date o xs:dateTime de una
colección de esquemas XML se actualizará automáticamente al valor más pequeño permitido por el tipo
base xs:date o xs:dateTime (por ejemplos, 0001-01-01T00:00:00.0000000Z para xs:dateTime).
Observe que todavía puede usar una instrucción SELECT de SQL para recuperar todo el tipo de datos XML, aun
cuando contiene años negativos. Se recomienda que reemplace los años negativos por un año dentro del
intervalo recientemente admitido o cambie el tipo del elemento o atributo a xs:string.
MÉTODOS DE TIPO DE DATOS XML
Puede utilizar los métodos del tipo de datos xml para realizar una consulta en una instancia XML almacenada en
una variable o columna de tipo xml. En los temas de esta sección se describe cómo utilizar los métodos del tipo
de datos xml.
En esta sección
Tema Descripción
query() (método de tipo de
datos xml)
Describe cómo utilizar el método query() para realizar una consulta en
una instancia XML.
value() (método del tipo de
datos xml)
Describe cómo utilizar el método value() para recuperar un valor de tipo
SQL de una instancia XML.
exist() (método del tipo de
datos xml)
Describe cómo utilizar el método exist() para determinar si una consulta
devuelve un resultado no vacío.
Modify() (método del tipo de
datos xml)
Describe cómo utilizar el método modify() para especificar instrucciones
XML Data Modification Language (XML DML) para realizar las
actualizaciones.
nodes() (método del tipo de
datos XML)
Describe cómo utilizar el método nodes() para dividir XML en varias filas,
lo que propaga partes de documentos XML en conjuntos de filas.
Enlazar datos relacionales
dentro de datos XML
Describe cómo enlazar datos no XML dentro de XML.
Directrices para utilizar los
métodos del tipo de datos xml
Describe instrucciones para utilizar los métodos de tipo de datos xml.
Estos métodos se llaman mediante la sintaxis de llamada de métodos de tipo definido por el usuario. Por
ejemplo:
SELECT XmlCol.query(' ... ')
FROM Table
query()
Especifica una expresión XQuery para una instancia de tipo de datos xml. El resultado es de tipo xml. El método
devuelve una instancia XML sin tipo.
Sintaxis
query ('XQuery')
Argumentos:
XQuery
Es una cadena, una expresión XQuery, que consulta nodos XML como, por ejemplo, elementos y atributos, en
una instancia XML.
Ejemplos:
Esta sección muestra ejemplos de cómo utilizar el método query() de tipo de datos xml.
A. Usar el método query() con una variable de tipo xml
El ejemplo siguiente declara una variable @myDoc de tipo xml y le asigna una instancia XML. A continuación,
se utiliza el método query() para especificar una expresión XQuery para el documento.
La consulta recupera el elemento secundario <Features> del elemento <ProductDescription>: declare @myDoc xml
set @myDoc = '<Root>
<ProductDescription ProductID="1" ProductName="Road Bike">
<Features>
<Warranty>1 year parts and labor</Warranty>
<Maintenance>3 year parts and labor extended maintenance is
available</Maintenance>
</Features>
</ProductDescription>
</Root>'
SELECT @myDoc.query('/Root/ProductDescription/Features')
El resultado es el siguiente: <Features>
<Warranty>1 year parts and labor</Warranty>
<Maintenance>3 year parts and labor extended maintenance is
available</Maintenance>
</Features>
B. Usar el método query() con una columna de tipo XML
En el ejemplo siguiente, el método query() se utiliza para especificar una expresión XQuery para la columna
CatalogDescription de tipo xml en la base de datos AdventureWorks: SELECT CatalogDescription.query('
declare namespace PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
<Product ProductModelID="{ /PD:ProductDescription[1]/@ProductModelID }" />
') as Result
FROM Production.ProductModel
where CatalogDescription.exist('
declare namespace PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
declare namespace wm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelWarrAndMain";
/PD:ProductDescription/PD:Features/wm:Warranty ') = 1
Observe lo siguiente en la consulta anterior:
La columna CatalogDescription es una columna xml con tipo. Esto quiere decir que tiene asociada una
colección de esquemas. En el prólogo de XQuery, la palabra clave namespace se utiliza para definir el
prefijo que se utilizará posteriormente en el cuerpo de la consulta.
El método query() crea XML, un elemento <Product> que tiene el atributo ProductModelID, en el que
el valor de atributo ProductModelID se recupera a partir de la base de datos. Para obtener más
información acerca de la creación de XML, vea Construcción de XML (XQuery).
El método exist() del tipo de datos xml en la cláusula WHERE se utiliza para buscar sólo filas que
contengan el elemento <Warranty> en el XML. La palabra clave namespace se utiliza nuevamente para
definir dos prefijos de espacios de nombres.
Éste es el resultado parcial: <Product ProductModelID="19"/>
<Product ProductModelID="23"/>
...
value() (método del tipo de datos xml)
Realiza una consulta XQuery en datos XML y devuelve un valor de tipo SQL. Este método devuelve un valor
escalar.
Normalmente, este método se utiliza para extraer un valor de una instancia XML almacenada en una columna,
parámetro o variable de tipo xml. De esta manera, se pueden especificar consultas SELECT que combinen o
comparen datos XML con datos de columnas que no son XML.
Sintaxis value (XQuery, SQLType)
Argumentos
XQuery
Es la expresión XQuery, un literal de cadena, que recupera los datos de la instancia XML. La expresión
XQuery debe devolver un valor como máximo. En caso contrario, se devuelve un error.
SQLType
Es el tipo SQL preferido, un literal de cadena, que se devuelve. El tipo de valor devuelto de este método
coincide con el parámetro SQLType. SQLType no puede ser un tipo de datos xml, un tipo definido por el
usuario de Common Language Runtime (CLR), image, text, ntext o un tipo de datos sql_variant.
SQLType puede ser un tipo de datos definido por el usuario SQL.
El método value() utiliza el operador CONVERT de Transact-SQL de manera implícita e intenta convertir el
resultado de la expresión XQuery, la representación de cadena serializada, del tipo XSD al tipo SQL
correspondiente especificado por la conversión Transact-SQL. Para obtener más información acerca de las reglas
de conversión de tipos de CONVERT, vea CAST y CONVERT (Transact-SQL).
Por motivos de rendimiento, en lugar de utilizar el método value() en un predicado para la comparación con un
valor relacional, utilice exist() con sql:column(). Esto se muestra en el ejemplo D a continuación.
Ejemplos
A. Utilizar el método value() con una variable de tipo xml
En el ejemplo siguiente, una instancia XML está almacenada en una variable de tipo xml. El método value()
recupera el valor del atributo ProductID en el XML. Después, el valor se asigna a una variable int. DECLARE @myDoc xml
DECLARE @ProdID int
SET @myDoc = '<Root>
<ProductDescription ProductID="1" ProductName="Road Bike">
<Features>
<Warranty>1 year parts and labor</Warranty>
<Maintenance>3 year parts and labor extended maintenance is
available</Maintenance>
</Features>
</ProductDescription>
</Root>'
SET @ProdID = @myDoc.value('(/Root/ProductDescription/@ProductID)[1]', 'int' )
SELECT @ProdID
Como resultado se devuelve el valor 1.
Aunque hay un solo atributo ProductID en la instancia XML, las reglas de los tipos estáticos requieren que se
especifique explícitamente que la expresión de ruta de acceso devuelva un singleton. Por tanto, se especifica [1]
al final de la expresión de ruta de acceso. Para obtener más información acerca de los tipos estáticos, vea
XQuery y el establecimiento de tipos estáticos.
B. Utilizar el método value() para recuperar un valor de una columna de tipo xml
La siguiente consulta se especifica sobre una columna de tipo xml (CatalogDescription) de la base de datos
AdventureWorks. La consulta recupera los valores del atributo ProductModelID de cada instancia XML
almacenada en la columna. SELECT CatalogDescription.value('
declare namespace
PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
(/PD:ProductDescription/@ProductModelID)[1]', 'int') AS Result
FROM Production.ProductModel
WHERE CatalogDescription IS NOT NULL
ORDER BY Result desc
Observe lo siguiente en la consulta anterior:
Se utiliza la palabra clave namespace para definir un prefijo de espacio de nombres.
Según los requisitos de los tipos estáticos, se agrega [1] al final de la expresión de ruta de acceso del
método value() para indicar explícitamente que la expresión de ruta de acceso devuelva un singleton.
Éste es el resultado parcial: -----------
35
34
...
C. Utilizar los métodos value() y exist() para recuperar valores de una columna de tipo xml
En el siguiente ejemplo se muestra el uso del método value() y el método exist() del tipo de datos xml. El
método value() se utiliza para recuperar los valores del atributo ProductModelID del XML. El método exist() de la
cláusula WHERE se utiliza para filtrar las filas de la tabla.
La consulta recupera los identificadores de modelo de producto de las instancias XML que incluyen información
de garantía (el elemento <Warranty>) entre sus características. La condición de la cláusula WHERE utiliza el
método exist() para recuperar únicamente las filas que cumplan esta condición. SELECT CatalogDescription.value('
declare namespace
PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
(/PD:ProductDescription/@ProductModelID)[1] ', 'int') as Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
declare namespace
PD="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
declare namespace
wm="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelWarrAndMain";
/PD:ProductDescription/PD:Features/wm:Warranty ') = 1
Observe lo siguiente en la consulta anterior:
La columna CatalogDescription es una columna XML con tipo. Esto significa que tiene asociada una
colección de esquemas. En el prólogo de las consultas XQuery, se utiliza la declaración del espacio de
nombres para definir el prefijo que se utilizará posteriormente en el cuerpo de la consulta.
Si el método exist() devuelve 1 (True), significa que la instancia XML incluye el elemento secundario
<Warranty> entre sus características.
Después, el método value() de la cláusula SELECT recupera los valores del atributo ProductModelID
como enteros.
Éste es el resultado parcial: Result
-----------
19
23
...
D. Utilizar el método exist() en lugar del método value()
Por motivos de rendimiento, en lugar de utilizar el método value() de un predicado para compararlo con un
valor relacional, utilice exist() con sql:column(). Por ejemplo: CREATE TABLE T (c1 int, c2 varchar(10), c3 xml)
GO
SELECT c1, c2, c3
FROM T
WHERE c3.value( '/root[1]/@a', 'integer') = c1
GO
Esto se puede escribir de la forma siguiente: SELECT c1, c2, c3
FROM T
WHERE c3.exist( '/root[@a=sql:column("c1")]') = 1
GO
exist() (método del tipo de datos xml)
Devuelve un bit que representa una de las condiciones siguientes:
1, que representa True, si la expresión XQuery de una consulta devuelve un resultado no vacío, es decir,
si devuelve al menos un nodo XML.
0, que representa False, si devuelve un resultado vacío.
NULL si la instancia con datos del tipo xml con la que se ejecuta la consulta incluye valores NULL.
El método exist() devuelve 1 para la expresión XQuery que devuelve un resultado no vacío. Si se especifican las
funciones true() o false() dentro del método exist(), el método exist() devolverá 1, porque las funciones true()
y false() devuelven los valores booleanos True y False respectivamente. En otras palabras, devuelven un
resultado no vacío. Por tanto, exist() devolverá 1 (True), como se muestra en el ejemplo siguiente:
declare @x xml set @x=''
select @x.exist('true()')
Sintaxis exist (XQuery)
Argumentos
XQuery
Es una expresión XQuery, un literal de cadena.
Ejemplos
En los ejemplos siguientes se muestra cómo especificar el método exist().
Ejemplo: especificar el método exist() con una variable de tipo xml
En el ejemplo siguiente, @x es una variable de tipo xml (xml sin tipo) y @f es una variable de tipo entero que
almacena el valor devuelto por el método exist(). El método exist() devuelve True (1) si el valor de fecha
almacenado en la instancia XML es 2002-01-01. declare @x xml
declare @f bit
set @x = '<root Somedate = "2002-01-01Z"/>'
set @f = @x.exist('/root[(@Somedate cast as xs:date?) eq xs:date("2002-01-01Z")]')
select @f
Al comparar las fechas del método exist(), tenga en cuenta lo siguiente:
El código cast as xs:date? se utiliza para convertir el valor al tipo xs:date con fines comparativos.
El valor del atributo @Somedate no tiene tipo. Al comparar este valor, se convierte implícitamente al
tipo de la derecha de la comparación, el tipo xs:date.
En lugar de cast as xs:date(), puede utilizar la función constructora xs:date(). Para obtener más
información, vea Funciones de constructor (XQuery).
El ejemplo siguiente es similar al anterior, con la diferencia de que tiene un elemento <Somedate>. DECLARE @x xml
DECLARE @f bit
SET @x = '<Somedate>2002-01-01Z</Somedate>'
SET @f = @x.exist('/Somedate[(text()[1] cast as xs:date ?) = xs:date("2002-01-
01Z") ]')
SELECT @f
Observe lo siguiente en la consulta anterior:
El método text() devuelve un nodo de texto que incluye el valor sin tipo 2002-01-01. El tipo XQuery es
xdt:untypedAtomic. Debe convertir explícitamente este valor con tipo de x a xsd:date, puesto que en
este caso no se admite la conversión implícita.
Ejemplo: especificar el método exist() con una variable xml con tipo
En el ejemplo siguiente se muestra el uso del método exist() con una variable del tipo xml. Se trata de una
variable XML con tipo, pues especifica el nombre de la colección del espacio de nombres del esquema,
ManuInstructionsSchemaCollection.
En este ejemplo, en primer lugar se asigna a esta variable un documento con instrucciones de fabricación y, a
continuación, se utiliza el método exist() para comprobar si el documento incluye un elemento <Location>
cuyo valor del atributo LocationID es 50.
El método exist() especificado con la variable @x devuelve 1 (True) si el documento con instrucciones de
fabricación incluye un elemento <Location> con LocationID=50. De lo contrario, el método devolverá 0 (False). DECLARE @x xml (Production.ManuInstructionsSchemaCollection)
SELECT @x=Instructions
FROM Production.ProductModel
WHERE ProductModelID=67
--SELECT @x
DECLARE @f int
SET @f = @x.exist(' declare namespace
AWMI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelManuInstructions";
/AWMI:root/AWMI:Location[@LocationID=50]
')
SELECT @f
Ejemplo: especificar el método exist() con una columna de tipo xml
La consulta siguiente recupera los Id. de modelo de producto cuyas descripciones de catálogo no incluyen las
especificaciones, elemento <Specifications>: SELECT ProductModelID, CatalogDescription.query('
declare namespace pd="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
<Product
ProductModelID= "{ sql:column("ProductModelID") }"
/>
') AS Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
declare namespace
pd="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelDescription";
/pd:ProductDescription[not(pd:Specifications)]'
) = 1
Observe lo siguiente en la consulta anterior:
La cláusula WHERE selecciona únicamente las filas de la tabla ProductDescription que satisfacen la
condición especificada en la columna de tipo CatalogDescription xml.
El método exist() de la cláusula WHERE devuelve 1 (True) si el XML no incluye ningún elemento
<Specifications>. Observe la utilización de la función de XQuery not().
La función de XQuery sql:column() se utiliza para recuperar el valor de una columna distinta de XML.
Esta consulta devuelve un conjunto de filas vacío.
Modify() (método del tipo de datos xml)
Modifica el contenido de un documento XML. Utilice este método para modificar el contenido de una columna
o variable de tipo xml. Este método toma una instrucción XML DML para insertar, actualizar o eliminar nodos a
partir de datos XML. El método modify() del tipo de datos xml sólo puede utilizarse en la cláusula SET de una
instrucción UPDATE.
Sintaxis modify (XML_DML)
Argumentos
XML_DML
Es una cadena en lenguaje de manipulación de datos (DML) XML. El documento XML se actualiza
conforme a esta expresión.
Se devuelve un error si se llama al método modify() sobre un valor NULL o da como resultado un valor NULL.
Ejemplos
Puesto que el método modify() requiere una cadena en el lenguaje de manipulación de datos (DML) XML, los
ejemplos de modify() se encuentran en los temas que tratan sobre las instrucciones XML DML. Para consultar
los ejemplos, vea insert (XML DML), delete (XML DML) y replace value of (XML DML).
nodes() (método del tipo de datos XML)
El método nodes() es muy útil si desea dividir una instancia de tipo de datos xml en datos relacionales. Permite
identificar nodos que se asignarán a una fila nueva.
Cada instancia de tipo de datos xml tiene un nodo de contexto proporcionado de manera implícita. En el caso
de la instancia XML almacenada en una columna o variable, éste es el nodo de documento. El nodo de
documento es el nodo implícito situado en la parte superior de cada instancia de tipo de datos xml.
El resultado del método nodes() es un conjunto de datos que contiene copias lógicas de las instancias XML
originales. En estas copias lógicas, el nodo de contexto de cada instancia de fila se establece en uno de los
nodos identificados con la expresión de consulta, de manera que las consultas posteriores pueden desplazarse
de forma relativa hasta estos nodos de contexto.
Puede recuperar varios valores del conjunto de filas. Por ejemplo, puede aplicar el método value() al conjunto
de filas devuelto por nodes() y recuperar varios valores de la instancia XML original. Tenga en cuenta que el
método value(), cuando se aplica a la instancia XML, devuelve sólo un valor.
Sintaxis nodes (XQuery) as Table(Column)
Argumentos
XQuery
Es un literal de cadena, una expresión XQuery. Si la expresión de consulta construye nodos, éstos se
exponen en el conjunto de filas resultante. Si la expresión de consulta da lugar a una secuencia vacía, el
conjunto de filas estará vacío. Si la expresión de consulta da lugar estáticamente a una secuencia que
contiene valores atómicos en lugar de nodos, se produce un error estático.
Table(Column)
Es el nombre de tabla y el nombre de columna del conjunto de filas resultante.
Notas
Por ejemplo, imagine que tiene la tabla siguiente: T (ProductModelID int, Instructions xml)
En la tabla se almacena el siguiente documento de instrucciones de fabricación. Sólo se muestra un fragmento.
Tenga en cuenta que hay tres ubicaciones de fabricación en el documento. <root>
<Location LocationID="10"...>
<step>...</step>
<step>...</step>
...
</Location>
<Location LocationID="20" ...>
...
</Location>
<Location LocationID="30" ...>
...
</Location>
</root>
La invocación del método nodes() con la expresión de consulta /root/Location devuelve un conjunto con tres
filas, de las que cada una contiene una copia lógica del documento XML original, y con el elemento de contexto
establecido en uno de los nodos <Location>: Product
ModelID Instructions
----------------------------------
1 <root>
<Location LocationID="20" ... />
<Location LocationID="30" .../></root>
1 <root><Location LocationID="10" ... />
<Location LocationID="30" .../></root>
1 <root><Location LocationID="10" ... />
<Location LocationID="20" ... />
</root>
A continuación, puede consultar este conjunto de filas utilizando métodos del tipo de datos xml. La siguiente
consulta extrae el subárbol del elemento de contexto de cada fila generada: SELECT T2.Loc.query('.')
FROM T
CROSS APPLY Instructions.nodes('/root/Location') as T2(Loc)
El resultado es el siguiente: ProductModelID Instructions
----------------------------------
1 <Location LocationID="10" ... />
1 <Location LocationID="20" ... />
1 <Location LocationID="30" .../>
Observe que el conjunto de filas devuelto ha mantenido la información de tipo. Puede aplicar métodos del tipo
de datos xml, como query(), value(), exist() y nodes(), al resultado de un método nodes(). Sin embargo, no
puede aplicar el método modify() para modificar la instancia XML.
Asimismo, el nodo de contexto del conjunto de filas no se puede materializar. Es decir, no puede utilizarlo en
una instrucción SELECT. Sin embargo, puede utilizarlo en IS NULL y COUNT(*).
Los escenarios para utilizar el método nodes() son los mismos que para utilizar OPENXML (Transact-SQL). Esto
proporciona una vista del conjunto de filas del documento XML. Sin embargo, no tiene que utilizar cursores
cuando utiliza el método nodes() en una tabla que contenga varias filas de documentos XML.
Observe que el conjunto de filas devuelto por el método nodes() no tiene nombre. Por tanto, se le debe dar un
nombre de manera explícita utilizando alias.
La función nodes() no puede aplicarse directamente a los resultados de una función definida por el usuario.
Para usar la función nodes() con el resultado de una función escalar definida por el usuario, puede asignar el
resultado de la función definida por el usuario a una variable o usar una tabla derivada para asignar un alias de
columna al valor devuelto de la función definida por el usuario y luego usar CROSS APPLY para seleccionar del
alias.
En el ejemplo siguiente se muestra una forma de usar CROSS APPLY para seleccionar entre los resultados de una
función definida por el usuario. USE AdventureWorks;
GO
CREATE FUNCTION XTest()
RETURNS xml
AS
BEGIN
RETURN '<document/>';
END;
GO
SELECT A2.B.query('.')
FROM
(SELECT dbo.XTest()) AS A1(X)
CROSS APPLY X.nodes('.') A2(B);
GO
DROP FUNCTION XTest;
GO
Ejemplos
Usar el método nodes() con una variable de tipo xml
En el siguiente ejemplo, hay un documento XML que incluye un elemento <Root> de nivel superior y tres
elementos secundarios <row>. La consulta utiliza el método nodes() para establecer nodos de contexto
independientes, uno para cada elemento <row>. El método nodes() devuelve un conjunto de tres filas. Cada fila
tiene una copia lógica del documento original, donde cada nodo de contexto identifica un elemento <row>
distinto del documento original.
La consulta devuelve después el nodo de contexto de cada fila: DECLARE @x xml
SET @x='<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>'
SELECT T.c.query('.') AS result
FROM @x.nodes('/Root/row') T(c)
GO
A continuación se muestra el resultado. En este ejemplo, el método de consulta devuelve el elemento de
contexto y su contenido:
<row id="1"><name>Larry</name><oflw>some text</oflw></row> <row id="2"><name>moe</name></row>
<row id="3"/>
Si se aplica el descriptor de acceso primario en los nodos de contexto, devuelve el elemento <Root> para los
tres: SELECT T.c.query('..') AS result
FROM @x.nodes('/Root/row') T(c)
go
El resultado es el siguiente: <Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>
Especificar el método nodes() con una columna de tipo xml
En este ejemplo se utilizan las instrucciones de fabricación de bicicletas y se almacenan en la columna
Instructions de tipo xml de la tabla ProductModel. Para obtener más información, vea Representación de tipo
de datos xml en la base de datos AdventureWorks.
En el siguiente ejemplo, el método nodes() se especifica para la columna Instructions de tipo xml de la tabla
ProductModel.
El método nodes() establece los elementos <Location> como nodos de contexto especificando la ruta de acceso
/MI:root/MI:Location. El conjunto de filas resultante incluye copias lógicas del documento original, una para
cada nodo <Location> del documento, con el nodo de contexto establecido en el elemento <Location>. Por
tanto, la función nodes() ofrece un conjunto de nodos de contexto <Location>.
El método query() sobre este conjunto de resultados solicita self::node y, por lo tanto, devuelve el elemento
<Location> de cada fila.
En este ejemplo, la consulta establece cada elemento <Location> como un nodo de contexto en el documento
de instrucciones de fabricación del modelo de producto específico. Puede utilizar estos nodos de contexto para
recuperar valores como los siguientes:
Buscar los Id. de ubicación de cada <Location>
Recuperar pasos de fabricación (elementos <step> secundarios) en cada <Location>
Esta consulta devuelve el elemento de contexto, en el que se especifica la sintaxis abreviada '.' para self::node(),
en el método query().
Tenga en cuenta lo siguiente:
El método nodes() se aplica a la columna Instructions y devuelve un conjunto de filas, T (C). Este
conjunto de filas contiene copias lógicas del documento de instrucciones de fabricación original con
/root/Location como elemento de contexto.
CROSS APPLY aplica nodes() a cada fila de la tabla Instructions y devuelve sólo las filas que producen un
conjunto de resultados. SELECT C.query('.') as result
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelManuInstructions";
/MI:root/MI:Location') as T(C)
WHERE ProductModelID=7
Éste es el resultado parcial: <MI:Location LocationID="10" ...>
<MI:step ... />
...
</MI:Location>
<MI:Location LocationID="20" ... >
<MI:step ... />
...
</MI:Location>
...
Aplicar nodes() al conjunto de filas devuelto por otro método nodes()
El código siguiente realiza una consulta en los documentos XML sobre instrucciones de fabricación en la
columna Instructions de la tabla ProductModel. La consulta devuelve un conjunto de filas que contiene el Id. del
modelo de producto, las ubicaciones y los pasos de fabricación.
Tenga en cuenta lo siguiente:
El método nodes() se aplica a la columna Instructions y devuelve el conjunto de filas T1 (Locations). Este
conjunto de filas contiene copias lógicas del documento de instrucciones de fabricación original con el
elemento /root/Location como contexto del elemento.
nodes() se aplica al conjunto de filas T1 (Locations) y devuelve el conjunto de filas T2 (steps). Este
conjunto de filas contiene copias lógicas del documento de instrucciones de fabricación original con el
elemento /root/Location/step como contexto del elemento. SELECT ProductModelID, Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelManuInstructions";
/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('
declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ProductModelManuInstructions";
./MI:step ') as T2(steps)
WHERE ProductModelID=7
GO
El resultado es el siguiente: ProductModelID LocID Step
----------------------------
7 10 <step ... />
7 10 <step ... />
...
7 20 <step ... />
7 20 <step ... />
7 20 <step ... />
...
Enlazar datos relacionales dentro de datos XML
Puede especificar Métodos de tipo de datos xml con una variable de tipo de datos o columna xml. Por ejemplo,
query() (método de tipo de datos xml) ejecuta la instrucción XQuery especificada con una instancia XML.
Cuando se genera XML de esta manera, se puede utilizar un valor de un tipo de columna que no es XML o una
variable Transact-SQL. Este proceso se conoce como enlazar datos relacionales dentro de XML.
Para enlazar datos relacionales no XML dentro de XML, el motor de base de datos de SQL Server proporciona
estas seudofunciones:
sql:column() (función de XQuery). Le permite utilizar los valores de una columna relacional en la
expresión XQuery o XML DML.
sql:variable() (función de XQuery). Le permite utilizar el valor de una variable de SQL en la expresión
XQuery o XML DML.
Estas funciones se pueden utilizar con métodos de tipo de datos xml siempre que se desee exponer un valor
relacional dentro de XML.
Estas funciones no se pueden utilizar para hacer referencia a datos en columnas o variables de tipo xml, de tipos
definidos por el usuario CLR, datetime, smalldatetime, text, ntext, sql_variant e image.
Asimismo, este enlace es de sólo lectura. En otras palabras, no se pueden escribir datos en las columnas que
utilicen estas funciones. Por ejemplo, no se permite sql:variable("@x")="alguna expresión".
Ejemplo: consulta entre dominios mediante sql:variable()
Este ejemplo muestra cómo sql:variable() puede permitir a una aplicación parametrizar una consulta. El ISBN se
pasa mediante una variable SQL @isbn. Sustituyendo la constante por sql:variable(), la consulta sirve para
buscar cualquier ISBN y no sólo el que corresponde a 0-7356-1588-2. DECLARE @isbn varchar(20)
SET @isbn = '0-7356-1588-2'
SELECT xCol
FROM T
WHERE xCol.exist ('/book/@ISBN[. = sql:variable("@isbn")]') = 1
sql:column() se puede utilizar de manera similar y ofrece otras ventajas. Los índices de la columna favorecen la
eficiencia, según lo decida el optimizador de consultas basado en costos. Además, la columna calculada puede
almacenar una propiedad promocionada.
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
sólo 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.
ESTABLECER OPCIONES (TIPO DE DATOS XML)
[Este tema pertenece a la documentación de la versión preliminar y está sujeto a cambios en versiones futuras.
Los temas en blanco se incluyen como marcadores de posición. NOTA: Con el fin de proporcionarle contenido
adicional en distintos idiomas, Microsoft ofrece documentación localizada mediante métodos de traducción
alternativos. Para esta versión preliminar, parte del contenido de esta documentación se ha traducido mediante
el uso de estos métodos. Microsoft es consciente de que los documentos traducidos de esta forma no son
siempre perfectos, por lo que es posible que este artículo contenga errores de vocabulario, sintaxis o gramática.
La versión final de este contenido se traducirá por los métodos tradicionales y la calidad será igual que la de las
versiones anteriores.]
Cuando se consultan variables o columnas de tipo xml utilizando métodos del tipo de datos xml, se deben
establecer las siguientes opciones como se indica.
Opciones SET Valores requeridos
ANSI_NULLS ON
ANSI_PADDING ON
ANSI_WARNINGS ON
ARITHABORT ON
CONCAT_NULL_YIELDS_NULL ON
NUMERIC_ROUNDABORT OFF
QUOTED_IDENTIFIER ON
Si no se establecen las opciones como se indica, no funcionarán las consultas y modificaciones de los métodos
del tipo de datos xml.
LENGUAJE DE MANIPULACIÓN DE DATOS XML (XML DML)
El Lenguaje de manipulación de datos XML (XML DML) es una extensión del lenguaje XQuery1. Según W3C, el
lenguaje XQuery carece de la parte de manipulación de datos (DML). El lenguaje XML DML que se presenta en
1 Soporte XQuery
El Lenguaje XML Query, o XQuery, es un lenguaje inteligente y robusto optimizado para la consulta de todos los tipos de datos XML. Con
XQuery, usted puede correr procesos de consultas contra variables y columnas de tipos de datos XML utilizando los últimos métodos de
asociación. Como muchos de los estándares XML, el World Wide Web Consortium (W3C) supervisa el desarrollo de XQuery. XQuery ha
evolucionado de un lenguaje llamado Quilt, el cual estaba basado en una variedad de otros lenguajes de consulta como por ejemplo XML
Path Language (XPath) versión 1.0, XQL, y SQL. Tambien contiene XPath 2.0 como un subgrupo. Por lo tanto, si usted tenía experiencia
utilizando XPath 1.0, puede capitalizar sus habilidades y no tendrá que aprender el nuevo lenguaje por completo. Sin embargo, existen
este tema, así como el lenguaje XQuery, proporciona un lenguaje de consultas y modificación de datos
completamente funcional que se puede utilizar con el tipo de datos xml.
La especificación XQuery actualmente contiene sintaxis y semántica para consultas, pero no para modificar
documentos XML. El XML Data Modification Language (DML) es una extensión de las características de XQuery
para modificación de datos. SQL Server 2005 Beta 2 incorpora tres palabras claves: insert, update, y delete. Cada
una de estas tres se utiliza dentro del método
modify() del tipo de datos XML.
XML DML agrega a XQuery las siguientes palabras clave, donde se distingue entre mayúsculas y minúsculas:
insert
delete
replace value of
Como se describe en Tipo de datos XML, se pueden crear variables y columnas de tipo xml y asignarles
documentos o fragmentos XML. Para modificar o actualizar estas instancias XML, realice el siguiente
procedimiento:
Utilice el método modify() del tipo de datos xml.
Especifique las instrucciones XML DML correspondientes en el método modify().
Tenga en cuenta que no se pueden insertar ni eliminar algunos atributos, y a veces tampoco es posible
modificar sus valores. Por ejemplo:
Para xml con tipo o sin tipo, los atributos son xmlns, xmlns:* y xml:base.
Sólo para xml con tipo, los atributos son xsi:nil y xsi:type.
Entre otras restricciones se pueden citar las siguientes:
Para xml con o sin tipo, se producirá un error al insertar el atributo xml:base.
Para xml con tipo, se producirá un error al eliminar y modificar el atributo xsi:nil. Para xml sin tipo, se
puede eliminar el atributo o modificar su valor.
Para xml con tipo, se producirá un error si se modifica el valor del atributo xs:type. Para xml sin tipo, se
puede modificar el valor del atributo.
Cuando se modifica una instancia XML con tipo, el formato final debe ser una instancia válida de ese tipo. En
caso contrario, se devuelve un error de validación.
INSERT
Inserta uno o más nodos identificados por Expression1 como nodos secundarios o del mismo nivel que el nodo
identificado por Expression2.
Sintaxis: insert
Expression1 (
{as first | as last} into | after | before
Expression2
)
Argumentos:
Expression1
Identifica uno o varios nodos que se van a insertar. Puede ser una instancia XML constante; una
referencia a una instancia del tipo de datos XML con tipo de la misma colección de esquemas XML en el
mejoras significativas que van más allá de XPath 1.0, como por ejemplo tipeo, funciones especiales, y soporte para mejor iteración, orden de
resultados, y construcción.
que se aplica el método modify; una instancia del tipo de datos XML sin tipo que utiliza una función
sql:column()/sql:variable() independiente; o una expresión XQuery. La expresión puede proporcionar un
nodo, y también un nodo de texto, o una secuencia ordenada de nodos. No se puede resolver en el
nodo raíz (/). Si la expresión da como resultado un valor o una secuencia de valores, los valores se
insertan como un solo nodo de texto y cada valor de la secuencia se separa con un espacio. Si se
especifican varios nodos como constante, los nodos se incluyen entre paréntesis y se separan mediante
comas. No es posible insertar secuencias heterogéneas, como una secuencia de elementos, atributos o
valores. Si Expression1 se resuelve en una secuencia vacía, no se produce ninguna inserción ni se
devuelven errores.
into
Los nodos identificados por Expression1 se insertan como descendientes directos (nodos secundarios)
del nodo identificado por Expression2. Si el nodo de Expression2 ya tiene uno o más nodos secundarios,
se debe utilizar as first o as last para especificar dónde se desea agregar el nuevo nodo. Se agregaría al
principio o al final de la lista de nodos secundarios respectivamente. Las palabras clave as first y as last
se omiten cuando se insertan atributos.
after
Los nodos identificados por Expression1 se insertan como nodos del mismo nivel justo después del
nodo identificado por Expression2. La palabra clave after no se puede utilizar para insertar atributos. Por
ejemplo, no se puede utilizar para insertar un constructor de atributos o devolver un atributo desde una
consulta XQuery.
before
Los nodos identificados por Expression1 se insertan como nodos del mismo nivel justo antes del nodo
identificado por Expression2. La palabra clave before no se puede utilizar cuando se insertan atributos.
Por ejemplo, no se puede utilizar para insertar un constructor de atributos o devolver un atributo desde
una consulta XQuery.
Expression2
Identifica un nodo. Los nodos identificados en Expression1 se insertan con respecto al nodo identificado
por Expression2. Puede ser una expresión XQuery que devuelva una referencia a un nodo que exista en
el documento al que se hace referencia actualmente. Si se devuelve más de un nodo, se produce un
error en la operación de inserción. Si Expression2 devuelve una secuencia vacía, no se produce ninguna
inserción ni se devuelven errores. Si Expression2 no es un singleton de manera estática, se devuelve un
error estático. Expression2 no puede ser una instrucción de procesamiento, un comentario ni un
atributo. Tenga en cuenta que Expression2 debe ser una referencia a un nodo existente en el documento
y no a un nodo construido.
DELETE
Elimina nodos de una instancia XML.
Sintaxis: delete Expression
Argumentos:
Expression
Es una expresión XQuery que identifica los nodos que se deben eliminar. Se eliminarán todos los nodos
seleccionados por la expresión y los nodos o valores incluidos en los mismos. Tal como se describe en
insert (XML DML), debe ser una referencia a un nodo existente en el documento. No puede ser un nodo
construido. La expresión no puede ser el nodo raíz (/). Si la expresión devuelve una secuencia vacía, no
se produce ninguna eliminación y no se devuelven errores.
REPLACE VALUE OF
Actualiza el valor de un nodo en el documento.
Sintaxis: replace value of
Expression1
with
Expression2
Argumentos:
Expression1
Identifica un nodo cuyo valor se va a actualizar. Debe identificar un solo nodo. Es decir, Expression1
debe ser un singleton estático. Si el XML tiene un tipo, el tipo del nodo debe ser simple. Si se
seleccionan varios nodos, se producirá un error. Si Expression1 devuelve una secuencia vacía, no se
reemplazará ningún valor y no se devolverá ningún error. Expression1 debe devolver un solo elemento
que incluya contenido de tipo simple (tipos de lista o atómicos), un nodo de texto o un nodo de
atributo. Expression1 no puede ser un tipo de unión, un tipo complejo, una instrucción de
procesamiento, un nodo de documento ni un nodo de comentario. De lo contrario, se devolverá un
error.
Expression2
Identifica el nuevo valor del nodo. Puede ser una expresión que devuelve un nodo de tipo simple,
puesto que se utilizará data() implícitamente. Si el valor es una lista de valores, la instrucción update
reemplazará el valor antiguo por la lista. Si se modifica una instancia XML con tipo, Expression2 debe ser
del mismo tipo o un subtipo de Expression1. De lo contrario, se devolverá un error. Si se modifica una
instancia XML sin tipo, Expression2 debe ser una expresión que se pueda atomizar. En caso contrario, se
devolverá un error.
TRABAJAR CON EL TIPO DE DATOS XML EN APLICACIONES
Controlar XML desde una columna de tipo XML usando ADO y SQL Server Native Client
Para usar componentes MDAC con el fin de obtener acceso a los tipos y características introducidos en SQL
Server 2005, debe establecer la propiedad de inicialización DataTypeCompatibility en la cadena de conexión
de ADO.
Por ejemplo, en el siguiente ejemplo de Visual Basic Scripting Edition (VBScript) se muestra el resultado de la
realización de una consulta a una columna de tipo de datos xml, Demographics, de la tabla Sales.Store de la
base de datos de ejemplo AdventureWorks. Específicamente, la consulta busca el valor de la instancia de esta
columna para la fila en la que CustomerID es igual a 3.
Const DS = "MyServer"
Const DB = "AdventureWorks"
Set objConn = CreateObject("ADODB.Connection")
Set objRs = CreateObject("ADODB.Recordset")
CommandText = "SELECT Demographics" & _
" FROM Sales.Store" & _
" WHERE CustomerID = 3" & _
" OR CustomerID = 4"
ConnectionString = "Provider=SQLNCLI10" & _
";Data Source=" & DS & _
";Initial Catalog=" & DB & _
";Integrated Security=SSPI;" & _
"DataTypeCompatibility=80"
'Connect to the data source.
objConn.Open ConnectionString
'Execute command through the connection and display
Set objRs = objConn.Execute(CommandText)
Dim rowcount
rowcount = 0
Do While Not objRs.EOF
rowcount = rowcount + 1
MsgBox "Row " & rowcount & _
vbCrLf & vbCrLf & objRs(0)
objRs.MoveNext
Loop
'Clean up.
objRs.Close
objConn.Close
Set objRs = Nothing
Set objConn = Nothing
Este ejemplo muestra cómo establecer la propiedad de compatibilidad de tipos de datos. De manera
predeterminada, se establece en 0 cuando se usa SQL Server Native Client. Después de establecer el valor en 80,
el proveedor de SQL Server Native Client hará que las columnas de tipo xml y las definidas por el usuario
aparezcan como tipos de datos de SQL Server 2000. Serán DBTYPE_WSTR y DBTYPE_BYTES, respectivamente.
SQL Server Native Client también debe estar instalado en el equipo cliente y la cadena de conexión debe
especificar que se use como proveedor de datos con "Provider=SQLNCLI10;...".
Para probar este ejemplo
1. Compruebe que SQL Server Native Client está instalado y que en el equipo cliente está disponible
MDAC 2.6 o versiones posteriores.
2. Compruebe que la base de datos de ejemplo AdventureWorks de SQL Server está instalada.
3. Copie el código que se mostró anteriormente en este tema y péguelo en su editor de texto o de código.
Guarde el archivo como HandlingXmlDataType.vbs.
4. Modifique la secuencia de comandos según sea necesario por la instalación de SQL Server y guarde los
cambios.
Por ejemplo, donde se especifique MyServer, debe sustituirlo por (local) o por el nombre real del
servidor en el que está instalado SQL Server.
5. Ejecute HandlingXmlDataType.vbs y ejecute la secuencia de comandos.
Los resultados serán similares a los de la siguiente salida de ejemplo:
Row 1
<StoreSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/StoreSurvey">
<AnnualSales>1500000</AnnualSales>
<AnnualRevenue>150000</AnnualRevenue>
<BankName>Primary International</BankName>
<BusinessType>OS</BusinessType>
<YearOpened>1974</YearOpened>
<Specialty>Road</Specialty>
<SquareFeet>38000</SquareFeet>
<Brands>3</Brands>
<Internet>DSL</Internet>
<NumberEmployees>40</NumberEmployees>
</StoreSurvey>
Row 2
<StoreSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/StoreSurvey">
<AnnualSales>300000</AnnualSales>
<AnnualRevenue>30000</AnnualRevenue>
<BankName>United Security</BankName>
<BusinessType>BM</BusinessType>
<YearOpened>1976</YearOpened>
<Specialty>Road</Specialty>
<SquareFeet>6000</SquareFeet>
<Brands>2</Brands>
<Internet>DSL</Internet>
<NumberEmployees>5</NumberEmployees>
</StoreSurvey>
Controlar XML desde una columna de tipo xml utilizando ADO.NET
Para controlar XML desde una columna de tipo de datos xml utilizando ADO.NET y Microsoft .NET Framework,
puede utilizar el comportamiento estándar de la clase SqlCommand. Por ejemplo, una columna de tipo de
datos xml y sus valores se pueden recuperar de la misma manera que se recupera cualquier columna SQL
utilizando una clase SqlDataReader. Sin embargo, si desea trabajar con el contenido de una columna de tipo de
datos xml como XML, primero tendrá que asignar el contenido a un tipo XmlReader.
Controlar una columna de tipo XML como parámetros mediante ADO.NET
Para controlar un tipo de datos XML pasado como un parámetro en ADO.NET y .NET Framework, puede
proporcionar el valor como una instancia del tipo de datos SqlXml. No es necesario realizar ningún control
especial, porque las columnas de tipo de datos xml de SQL Server pueden aceptar valores de parámetros del
mismo modo que otros tipos de columnas y de datos, por ejemplo, string o integer.
REPRESENTACIÓN DE TIPO DE DATOS XML EN LA BASE DE DATOS ADVENTUREWORKS
La base de datos AdventureWorks tiene varias columnas de tipo xml. La siguiente tabla muestra los temas de
esta sección que describen estas columnas. Estas columnas se utilizan en varias consultas de ejemplo de los
Libros en pantalla de SQL Server.
Cada tema proporciona una instancia de ejemplo de datos XML almacenados en las columnas. La mayoría son
columnas XML con tipo. Estos temas ofrecen la colección de esquemas XML que se utiliza para escribir estas
columnas. Para entender las consultas especificadas, debe revisar los datos XML almacenados en estas
columnas.
Para ver cada una de los esquemas de la base AdventureWorks se puede utilizar USE AdventureWorks
GO
SELECT *
FROM sys.xml_schema_collections
Resultado obtenido:
AdditionalContactInfoSchemaCollection
IndividualSurveySchemaCollection
HRResumeSchemaCollection
ProductDescriptionSchemaCollection
ManuInstructionsSchemaCollection
StoreSurveySchemaCollection
Para ver los tipos de cada esquema XML utilice SELECT xml_schema_namespace(N'Person',N'AdditionalContactInfoSchemaCollection')
GO
SELECT xml_schema_namespace(N'Sales',N'IndividualSurveySchemaCollection')
GO
SELECT xml_schema_namespace(N'HumanResources',N'HRResumeSchemaCollection')
GO
SELECT xml_schema_namespace(N'Production',N'ProductDescriptionSchemaCollection')
Go
SELECT xml_schema_namespace(N'Production',N'ManuInstructionsSchemaCollection')
GO
SELECT xml_schema_namespace(N'Sales',N'StoreSurveySchemaCollection')
GO
La salida será un esquema XML, este es el ejemplo para el AditionalContactInfoSchemaColection <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactInfo"
targetNamespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactInfo">
<xsd:element name="AdditionalContactInfo">
<xsd:complexType mixed="true">
<xsd:complexContent mixed="true">
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:any
namespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactRecord http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactTypes" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactRecord"
targetNamespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactRecord">
<xsd:element name="ContactRecord">
<xsd:complexType mixed="true">
<xsd:complexContent mixed="true">
<xsd:restriction base="xsd:anyType">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:any
namespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactTypes" />
</xsd:choice>
<xsd:attribute name="date" type="xsd:date" />
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:t="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactTypes"
targetNamespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactTypes" elementFormDefault="qualified">
<xsd:element name="eMail" type="t:eMailType" />
<xsd:element name="facsimileTelephoneNumber" type="t:phoneNumberType" />
<xsd:element name="homePostalAddress" type="t:addressType" />
<xsd:element name="internationaliSDNNumber" type="t:phoneNumberType" />
<xsd:element name="mobile" type="t:phoneNumberType" />
<xsd:element name="pager" type="t:phoneNumberType" />
<xsd:element name="physicalDeliveryOfficeName" type="t:addressType" />
<xsd:element name="registeredAddress" type="t:addressType" />
<xsd:element name="telephoneNumber" type="t:phoneNumberType" />
<xsd:element name="telexNumber" type="t:phoneNumberType" />
<xsd:complexType name="addressType">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="Street" type="xsd:string" maxOccurs="2" />
<xsd:element name="City" type="xsd:string" />
<xsd:element name="StateProvince" type="xsd:string" />
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0" />
<xsd:element name="CountryRegion" type="xsd:string" />
<xsd:element name="SpecialInstructions" type="t:specialInstructionsType"
minOccurs="0" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="eMailType">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="eMailAddress" type="xsd:string" />
<xsd:element name="SpecialInstructions" type="t:specialInstructionsType"
minOccurs="0" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="phoneNumberType">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="number">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9\(\)\-]*" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="SpecialInstructions" type="t:specialInstructionsType"
minOccurs="0" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="specialInstructionsType" mixed="true">
<xsd:complexContent mixed="true">
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:any
namespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-
works/ContactTypes" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>