Directiva TYPE en consultas FOR XML

En SQL Server 2000, el resultado de una consulta FOR XML se devuelve siempre directamente al cliente en forma de texto. Gracias a la compatibilidad con el tipo de datos xml de SQL Server 2005, existe la opción de solicitar la devolución del resultado de una consulta FOR XML como tipo de datos xml especificando la directiva TYPE. Esto permite procesar el resultado de una consulta FOR XML en el servidor. Por ejemplo, puede especificar una XQuery en el mismo, asignar el resultado a una variable de tipo xml o escribir consultas FOR XML anidadas.

[!NOTA] SQL Server devuelve al cliente datos de instancia de tipo XML como resultado de distintas construcciones de servidor, por ejemplo consultas FOR XML que utilizan la directiva TYPE o en las que se utiliza el tipo de datos xml para devolver valores de datos de instancia XML procedentes de columnas de tablas SQL y parámetros de salida. En el código de las aplicaciones cliente, el proveedor ADO.NET solicita que se envíe esta información de tipo de datos XML con una codificación binaria desde el servidor. Sin embargo, si utiliza FOR XML sin la directiva TYPE, se devolverán los datos XML en forma de cadena. En cualquier caso, el proveedor del cliente siempre podrá controlar cualquier formato de tipo XML.

Ejemplos

En los ejemplos siguientes se ilustra el uso de la consulta FOR XML.

A. Recuperar resultados de consulta FOR XML en forma de xml

En la consulta siguiente se recupera información de contacto de clientes de la tabla Contacts. Puesto que se especifica la directiva TYPE en FOR XML, el resultado se devuelve como xml.

SELECT ContactID, FirstName, LastName, Phone
FROM Person.Contact
ORDER BY ContactID
FOR XML AUTO, TYPE

Éste es el resultado parcial:

<Contact ContactID="1" FirstName="Syed" LastName="Abbas" 
         Phone="398-555-0132"/>
<Contact ContactID="2" FirstName="Catherine" LastName="Abel" 
         Phone="747-555-0171"/>
...

B. Asignar resultados de consultas FOR XML a una variable de tipo xml

En el ejemplo siguiente, se asigna un resultado FOR XML a una variable de tipo xml, @x. La consulta recupera información de contacto, como ContactID, FirstName, LastName y números de teléfono adicionales, de la columna AdditionalContactInfo de tipo xml . Puesto que la cláusula FOR XML especifica la directiva TYPE, se devuelve XML en forma de xml y se asigna a una variable.

DECLARE @x XML
SET @x = (
   SELECT ContactID, 
          FirstName, 
          LastName, 
          AdditionalContactInfo.query('
declare namespace aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";
declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";
              //act:telephoneNumber/act:number') as MorePhoneNumbers
   FROM Person.Contact
   FOR XML AUTO, TYPE)
SELECT @x
GO

C. Consultar resultados de una consulta FOR XML

Las consultas FOR XML devuelven XML. Por tanto, puede aplicar métodos del tipo xml, como query() y value(), al resultado XML devuelto por las consultas FOR XML.

En la consulta siguiente, se utiliza el método query() del tipo de datos xml para consultar el resultado de la consulta FOR XML. Para obtener más información, vea query() (método de tipo de datos xml).

SELECT (SELECT ContactID, FirstName, LastName, AdditionalContactInfo.query('
declare namespace aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";
declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";
 //act:telephoneNumber/act:number
') as PhoneNumbers
FROM Person.Contact
FOR XML AUTO, TYPE).query('/Person.Contact[1]')

La consulta interna SELECT … FOR XML devuelve un resultado del tipo xml al que la consulta SELECT exterior aplica el método query() con el tipo xml. Observe la directiva TYPE especificada.

El resultado es el siguiente:

<Person.Contact ContactID="1" FirstName="Gustavo" LastName="Achong">
  <PhoneNumbers>
    <act:number xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">111-111-1111</act:number>
    <act:number xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">112-111-1111</act:number>
  </PhoneNumbers>
</Person.Contact>

En la consulta siguiente, el método query() del tipo de datos xml se utiliza para recuperar un valor del resultado XML devuelto por la consulta SELECT…FOR XML. Para obtener más información, vea value() (método del tipo de datos xml).

declare @FirstPhoneFromAdditionalContactInfo varchar(40);
SELECT @FirstPhoneFromAdditionalContactInfo = 
 ( SELECT ContactID, FirstName, LastName, AdditionalContactInfo.query('
declare namespace aci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";
declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";

   //act:telephoneNumber/act:number
   ') as PhoneNumbers
   FROM Person.Contact Contact
   FOR XML AUTO, TYPE).value('
declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";
  /Contact[@ContactID="1"][1]/PhoneNumbers[1]/act:number[1]', 'varchar(40)'
 )
select @FirstPhoneFromAdditionalContactInfo

La expresión de ruta de acceso XQuery del método value() recupera el primer número de teléfono de un contacto de cliente cuyo ContactID es 1.

[!NOTA] Si no se especifica la directiva TYPE, se devolverá el resultado de la consulta FOR XML con el tipo nvarchar(max).

D. Utilizar resultados de consultas FOR XML en INSERT, UPDATE y DELETE (DML de Transact-SQL)

En el ejemplo siguiente se muestra el modo en el que se pueden utilizar las consultas FOR XML en instrucciones del lenguaje de manipulación de datos (DML). En este ejemplo, FOR XML devuelve una instancia del tipo xml. La instrucción INSERT inserta esta instancia de tipo XML en una tabla.

CREATE TABLE T1(intCol int, XmlCol xml)
go
INSERT INTO T1 
VALUES(1, '<Root><ProductDescription ProductModelID="1" /></Root>')
go

CREATE TABLE T2(XmlCol xml)
go
INSERT INTO T2(XmlCol) 
SELECT (SELECT XmlCol.query('/Root') 
        FROM T1 
        FOR XML AUTO,TYPE) 
go