Hace poco, necesité escribir una consulta en una base de datos que requería el uso de unos datos que están publicados en un URL en forma de un archivo XML. Como necesitaba los datos en forma de tabla, para unirla a otras tablas existentes en mi base datos, decidí que era mejor usar una funcion que retorne una tabla, en lugar de un procedimiento almacenado.

La estructura del archivo XML era algo asi:

Además, hay un archivo diferente por año. Es decir que si necesito ver las publicaciones del año 2000, tendria que abrir el archivo necesario de esta forma: http://myURL/publicaciones_2000.xml y el archivo del año 2011: http://myURL/publicaciones_2011.xml.

Lo único que me interesa de este archivo son los códigos de los libros, porque los voy a usar en una consulta en mi base de datos que contiene estos códigos y otra información.

Entonces, mi función T-SQL será utilizada de ésta forma:

select codigo from dbo.LibrosPorAño(2000);

Para esto, creo el proyecto en Visual Studio, añado un nuevo elemento de tipo User-Defined Function  y uso el siguiente código:

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using System.Net;
using System.Xml.Linq;


public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName="FillRows", TableDefinition="codigo nvarchar(100)")]
public static IEnumerable LibrosPorAño(String Año)
{
List<string> codigos = GetDataFromXML(Año);
return codigos;
}
public static List<string> GetDataFromXML(string año)
{
String url = string.Format(@"http://myURL/publicaciones_{0}.xml", año);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
Stream stream = request.GetResponse().GetResponseStream();
StreamReader strRead = new StreamReader(stream);
XDocument xdoc = XDocument.Load(strRead);
List<string> results = new List<string>();
foreach (XElement el in xdoc.Descendants("Libros").Descendants("Codigo"))
{
results.Add(el.Value);
}

return results;
}
public static void FillRows(Object obj, out SqlChars año)
{
año = new SqlChars((string) obj);
}
};

En las propiedades del proyecto, en la seccion Database, cambio el Permission Level a External.

En mi base de datos, tengo que habilitar integración CLR y cambiar la opción Trustworthy de mi base de datos:

 SP_CONFIGURE 'CLR ENABLED', 1
GO
RECONFIGURE
GO


ALTER DATABASE TEST SET TRUSTWORTHY ON;
 

En Visual Studio, compilo mi proyecto y hago el deployment a mi base de datos.

Despues de comprobar que la función esta disponible en mi base de datos, mi tabla con los códigos de libros está lista para ser usada: