Reporting Service es gratuito?

Muchas veces se me hace esta pregunta o bien veo en foros la misma. La respuesta es SI. En la edición Express Advance Services es totalmente gratuita e incluye Reporting Service (ya sea 2005 o 2008).

Claro esta edición tiene algunas limitaciones pero lo que si es cierto que pueden desarrollar reportes tan complejos como en las ediciones Standard o Enterprise y luego si desean migrar a cualquier de estas ediciones no es necesario modificar nada de sus reportes.

La confusión por lo general viene ya que hay dos versiones de la edición Express de SQL (la común y la Advance Service) siendo solo esta ultima la que dispone de Reporting Service.

Aquí les dejo los links para poder descargar la Express 2005 o 2008

Etiquetas de Technorati: Reporting Service

Reporting Service 2008 desde 0

Los días 10 y 11 de Octubre he estado en la hermosa ciudad de Córdoba haciendo una conferencia para el Club de usuarios Microsoft (MUG) sobre Reporting Service 2008.

Primero quiero agradecer a los participantes de las jornadas ya que considerando que en argentina era un fin de semana largo han estado tanto el día viernes como el sábado por la mañana.

Aquí dejo el link al material utilizado en dichas jornadas, espero lo disfruten.

Como generar el numero de nuestros comprobantes sin morir en el intento

En la mayoria de nuestras aplicaciones tenemos la necesidad de poder generar el numero de nuestros comprobantes (Ordenes de compra, pedidos de ventas, etc)


Existen diferentes tecnicas para poder realizar esta operacion. En los ejemplos de este post mostrate las dos formas mas tradicionales de hacerlo y cuales son sus pros y contras de cada una.


Para estos ejemplos crearemos una base de datos nueva con la siguiente sentencia


CREATE DATABASE EJEMPLO_NUMERACION


Usando autonumericos


Dentro de SQLserver podemos definir en un tipo de dato entero la posibilidad de que sea autoincremental, esto hara que de forma automatica el motor de base de datos calcule el valor que debe ir en ese campo. Usando esta posibilidad podriamos definir que en nuestros comprobantes el campo de numero sea autonumerico.


El siguiente ejemplo ilustra como hacer esta operacion


USE EJEMPLO_NUMERACION


GO


CREATE TABLE OC (ID INT IDENTITY, FECHA DATETIME NOT NULL,


CLIENTE VARCHAR(50) NOT NULL)


GO


Como se podra observer el campo ID es de tipo int y a su vez tiene la propiedad de ser autoincremental, el resto de los campos corresponden a datos necesarios de la Orden de compra de este ejemplo.


Si queremos insertar un nuevo registro (o sea una nueva orden de compra) simplemente hacemos lo siguiente


INSERT INTO OC (FECHA,CLIENTE)


VALUES (GETDATE(),‘IBM’)


go


Si luego de esto hacemos un select a la tabla OC y vemos los registros podremos observar que se ha generado de forma automatica el ID 1, si hacemos otro insert valido veremos que se generara el 2 y asi sucesivamente.


Ahora bien, que sucede si por ejemplo hacemos un insert y no se pudo realizar la transaccion, por ejemplo queremos insertar una OC donde el campo Cliente sea nulo lo cual no esta permitido por  la integridad de la base de datos.


INSERT INTO OC (FECHA,CLIENTE)


VALUES (GETDATE(),NULL)


go


Al hacer esta instruccion recibiremos el siguiente error:


Msg 515, Level 16, State 2, Line 2


Cannot insert the value NULL into column ‘CLIENTE’, table ‘EJEMPLO_NUMERACION.dbo.OC’; column does not allow nulls. INSERT fails.


 


Bien, el registro si hacemos un select a la tabla no se ha generado y eso es correcto ya que ha existido un problema.


Ahora bien, hasta el momento solo tenemos generada la OC con ID = 1 y la 2 ha fallado. Pues arreglamos el tema del null en el insert para que se genere la OC = 2 ya que es la que continua luego de la 1.


INSERT INTO OC (FECHA,CLIENTE)


VALUES (GETDATE(),‘MICROSOFT’)


go


El registro se genero ahora “correctamente”, pero si hacemos un select a la tabla nos encontraremos que ahora tenemos el ID = 1 y el ID = 3, con lo cual estamos teniendo huecos en nuestra numeracion.


Como se podra observar es un grave problema tener estos huecos en los numeros de los comprobantes (imagine que fueran facturas por ejemplo), pues esto se debe a como funciona el autonumero de SQLServer, es simple de usar e implementar pero hay que saber lo de las transacciones, ante una falla el numero lo reservo igual y considero que se genero con lo cual lo salta [:(] 


Usando tabla numeradora


Otra alternativa a la que vimos es la de generar una tabla donde tendremos los numeros de los comprobantes y usarla para numerar uno nuevo, si la transaccion fallo simplemente hay que tener el recaudo de no cambiar el valor en la tabla numeradora.


Entonces, lo primero que generamos es esta tabla numeradora


CREATE TABLE NUMERADOR (TIPO_COMPROBANTE VARCHAR(100),


ULTIMO_NUMERO INT)


GO


INSERT INTO NUMERADOR VALUES (‘OC’,1)


INSERT INTO NUMERADOR VALUES (‘FACTURAS’,10)


GO


La tabla numeradora podra ser utilizada por distintos comprobantes, de ahi es que tiene un campo denominado tipo_comprobante y otro ultimo_numero.


Como tambien se puede observar se le han insertado 2 registros, uno para los comprobantes de Ordendes de Compra y el otro para facturas.


Ahora bien, lo que debemos hacer como siguiente paso es utilizar esta tabla numeradora para obtener el ultimo_numero sumarle 1 y asignarlo a la OC que estamos generando. Aqui entran a jugar una serie mas de detalles a conocer, si hacemos un Select (sin cambiar el nivel de bloqueo) y otro usuario en otro sitio hace lo mismo podran obtener el mismo ultimo_numero lo cual al sumarle 1 los dos intentaran hacer la misma OC.


Para evitar este tipo de situaciones, ya que no solo necesito numerar sino tambien asegurar que no exista la posibilidad de obtener numeros duplicados (la misma OC por ejemplo) es que vamos a hacer uso de algunos trucos de bloqueos y variables.


DROP TABLE OC


GO


CREATE TABLE OC (NUMERO INT, FECHA DATETIME,CLIENTE VARCHAR(50) NOT NULL)


GO

declare @proximo_numero int
begin try

begin tran



update numerador set @proximo_numero = ultimo_numero = ultimo_numero + 1


where tipo_comprobante = ‘OC’

INSERT INTO OC VALUES (@proximo_numero,getdate(),‘SQLTOTAL’)

commit tran

end try

begin catch



rollback tran — primero hacemos un rollback


print @@error — mostramos el error generado


end catch


GO


La sentencia UPDATE no solo modifica la tabla sino que ademas actualiza la variable que luego utilizamos para generar el comprobante. De esta manera logramos que si hay 2 procesos haciendo esto por el uso de los bloqueos internos de SQL al hacer uso de la instruccion UPDATE, el segundo proceso no podra hacer update hasta que el primero no haya terminado la transaccion (ya sea por commit o rollback tran)


Si hacemos un select sobre OC vamos a observar que se ha generado el id numero 2, ahora bien si intentamos hacer un nuevo insert pero que falla y luego volvemos a insertar uno que no falla no tendremos los huecos en la numeracion como nos ha sucedido con los identity.


Para probar que no se van a generar 2 numeros iguales en tiempos iguales hay que hacer la siguiente prueba con el Script.


1) Habra dos ventanas de management studio o Query Analizer si usa 2000


2) En ambas copie por ejemplo este codigo

declare @proximo_numero int begin try

begin tran



update numerador set @proximo_numero = ultimo_numero = ultimo_numero + 1


where tipo_comprobante = ‘OC’

INSERT INTO OC VALUES (@proximo_numero,getdate(),‘SQLTOTAL’)
end try

begin catch



rollback tran — primero hacemos un rollback


print @@error — mostramos el error generado


end catch


3) Ejecute desde la primer ventana el script, luego hagalo desde la segunda. Como podra observar en la segunda ventana se queda esperando y no procesa , esto se debe que hay bloqueos sobre la tabla numeradora y que el segundo update no ha podido ser realizado.


4) En la primer ventana escriba commit tran y ejecute solo eso


Al hacer esto podra observar que la segunda ventana ha terminado.


5) Haga un select sobre OC y vea los resultados [:)]


 


Bueno con esto termino, espero que les haya sido de utilidad y espero sus comentarios 


 


 

Sql Dinamico y seguridad en SQL2005

 


SQL-Dinámico y seguridad dentro de SQLServer 2005


El SQL-dinámico es una técnica la cual nos permite ejecutar sentencias TSQL de forma dinámica,  para poder hacer uso de esta técnica es necesario utilizar o bien el store procedure sp_executesql o sino EXEC(@str).


Este articulo no tiene como objetivo entrar en detalle del SQL-dinámico ya que hay otros escritos al respecto como por ejemplo el siguiente link el cual recomiendo leer


http://www.hayes.ch/sql/sql_dinamico.html


Aquí nos concentraremos en la seguridad y los cambios que hay en SQL2005 al respecto.


Una de las mayores contras que tiene el uso de SQL-Dinámico es que si lo ponemos dentro de un Store Procedure el usuario que ejecute tal Store no solo deberá tener permisos de execute sino que también deberá tener permisos sobre los objetos que haga referencia el SQL-Dinámico.


Para poder ser más específicos veamos un ejemplo al respecto


USE MASTER


GO

CREATE DATABASE TEST1

GO

USE TEST1

GO


— CREAMOS UN NUEVO LOGIN


CREATE LOGIN FEDERICO WITH PASSWORD =‘PASSW@RD’


GO

USE TEST1

GO


— CREAMOS EL USUARIO EN LA BASE DE DATOS

CREATE USER FEDERICO

GO


— CREAMOS UNA TABLA


CREATE TABLE DBO.EMPLEADOS (ID INT IDENTITY, NAME VARCHAR(50))


GO


— CREAMOS UN STORE QUE CONSUME LA TABLA EMPLEADOS


CREATE PROC DBO.USP_EMPLEADOS_GET_ALL AS

SELECT * FROM DBO.EMPLEADOS

GO


— CREAMOS OTRO STORE QUE CONSUME LA TABLA PERO CON SQLDINAMICO


CREATE PROC DBO.USP_EMPLEADOS_GET_ALL2 AS


DECLARE @N NVARCHAR(50)


SET @N = N‘SELECT * FROM DBO.EMPLEADOS’

EXECUTE SP_EXECUTESQL @N

GO


— FEDERICO SOLO TIENE PERMISOS A LOS STORES


GRANT EXECUTE ON DBO.USP_EMPLEADOS_GET_ALL TO FEDERICO

GRANT EXECUTE ON DBO.USP_EMPLEADOS_GET_ALL2 TO FEDERICO

GO


— ENTRAMOS COMO FEDERICO


EXECUTE AS LOGIN = ‘FEDERICO’


SELECT SUSER_SNAME()


SELECT * FROM DBO.EMPLEADOS — FALLA PORQUE NO TENEMOS PERMISO


EXEC DBO.USP_EMPLEADOS_GET_ALL — FUNCIONA


EXEC DBO.USP_EMPLEADOS_GET_ALL2 — FALLA POR EL SQL-DINAMICO


REVERT — REVERTIMOS EL LOGIN


Como se ha podido observar en el ejemplo el segundo Store ha fallado cuando el usuario Federico lo invoco ya que no tenia permisos sobre los objetos internos del mismo, en este caso la tabla “Empleados”.


Esto atenta contra el buen uso de un Store procedure ya que una de sus virtudes es aislar a los usuarios del acceso directo a los objetos, con lo cual si deseamos en este caso usar SQL-Dinámico deberíamos darle permisos de Select a la tabla correspondiente.


Esto funciona así en 2000 y no hay solución al respecto, por lo cual yo no recomiendo mucho el uso de SQL-Dinámico y de usarlo tener en claro lo que está sucediendo.


¿Que cambios hay en 2005?


SqlServer 2005 permite dentro de un objeto como el Store Procedure indicarle el contexto de ejecución, esto es totalmente nuevo y se indica con la sentencia WITH EXECUTE AS (Caller, Owner o Username)



  • Caller es utilizado por defecto y representa a quien llama (como vimos en el ejemplo 1)

  • Owner indica que se impersonificara como el usuario propietario del objeto, en este caso como entre con la cuenta de SA entonces estamos impersonificando con ella.

  • User_name nos permite indicar con que login deseamos que se impersonifique

 


El siguiente ejemplo modifica el  Store con SQL Dinámico pero utilizando Execute AS


— CAMBIOS EL STORE DEL SQL DINAMO PARA QUE SE EJECUTE EN


— OTRO CONTEXTO DE SEGURIDAD

ALTER PROC DBO.USP_EMPLEADOS_GET_ALL2

WITH EXECUTE AS OWNER


AS


DECLARE @N NVARCHAR(50)


SET @N = N‘SELECT * FROM DBO.EMPLEADOS’

EXECUTE SP_EXECUTESQL @N

GO


— VOLVEMOS A PROBAR


EXECUTE AS LOGIN = ‘FEDERICO’


SELECT SUSER_SNAME()


SELECT * FROM DBO.EMPLEADOS — FALLA PORQUE NO TENEMOS PERMISO


EXEC DBO.USP_EMPLEADOS_GET_ALL


EXEC DBO.USP_EMPLEADOS_GET_ALL2


REVERT


Aquí se ve claramente que ahora Federico no necesito permisos sobre la tabla “Empleados” para poder hacer uso del SQL-Dinámico.


Con esto lo que logramos es seguir manteniendo una de las enormes virtudes que tienen los Stores Procedures que es el aislamiento con respecto a los objetos base.


No confundir el Execute AS del Store con el luego utilizado en el query para dentro del management Studio impersonificarnos como Federico sin la necesidad entrar a otra ventana.


Estos ejemplos deben ser probados desde SQL2005, si desea probar el primer ejemplo desde SQL2000 deberá sacar la sentencia Execute AS y probar la seguridad entrando con el correspondiente login y password.


Bueno espero les sea de utilidad y espero sus comentarios.


Nos vemos!

Como crear el tipo de datos Hora en SQLServer 2005

 


Creando el tipo de datos hora en SQL2005 usando CLR


 


Introducción


 


SQLServer dispone de dos tipos de datos que son útiles para el almacenamiento de fechas y horas (Datetime & SmallDatetime). En muchas ocasiones necesitamos tener un tipo de datos exclusivo para almacenar únicamente las horas como así también poder hacer su tratamiento como podrían ser sumas, restas, promedios, etc.


En este articulo veremos paso a paso como crear nuestro propio tipo de datos hora y poderlo utilizar como si fuere cualquier otro tipo de dato del motor nativo.


 


CLR en SQL2005


 


Una de las mayores incorporaciones que se le ha hecho a SQLServer 2005 es la posibilidad de crear objetos SQL (Triggers – Stores Procedures – User Function – User defined Type – Aggregate Function) utilizando .NET. La siguiente tabla muestra los tipos de objetos que se pueden crear con T-SQL y/o CLR.


 




























Tipo de Objeto


TSQL


CLR


Store Procedures


X


X


Triggers


X


X


User Function


X


X


User Defined Type


 


X


Aggregate Function


 


X


 


Como se podrá observar si se desean crear “User defined Type” o bien “Aggregate Function” (como por ej. Sum, Avg, count,etc) es necesario hacerlos con CLR exclusivamente.


 


En este articulo no entraremos en detalle de cómo funciona el CLR dentro de SQL2005 sino que nos concentraremos en como crear un  “User Defined Types”  (UDT)


Debemos aclarar que no es necesario utilizar Visual Studio para poder programar en CLR dentro de SQL2005  pero si altamente recomendado por todas las facilidades que esta herramienta nos ofrece (Deploy – Debug , etc).


 


Al instalar SQL2005 por default no se activa el uso del CLR, esto es debido a que SQL2005 tiene como concepto “Seguro por defecto” con lo cual cierra todo tipo de funciones que pueden ser de alto riesgo.


Para poder habilitar el uso del CLR se puede o bien utilizar el SAC (Sourface Area Configuration) o sino la siguiente sentencia TSQL.


 


EXEC sp_configure ‘show advanced options’, 1


GO


RECONFIGURE


GO


sp_configure ‘clr enabled’, 1


GO


RECONFIGURE


GO


 



Fig 1 Sourface Area Configuration


 


Descripción de los User Defined Types


 


En versiones anteriores a SQL2005 los UDT eran solamente Alias de otro tipo de dato como se muestra en el siguiente código.


 


EXEC sp_addtype N’age’, N’tinyint’, N’not null’


GO


 


CREATE RULE age_range


AS


@age >= 0 AND @age <=140


GO


 


EXEC sp_bindrule N’age_range’, N’age’


GO


 


Ahora en SQL2005 los UDT son muchos mas ricos donde todo el comportamiento esta embebido en el código de este.


Los UDT deben respetar los siguientes requerimientos


 



  • Soportar el concepto de Null (INullable)

  • Soportar la conversión hacia y desde String

  • Soportar la serialización

  • Soportar un constructor por default

  • Respetar las reglas de nombres (128 caracteres máximo)

Creando el UDT desde Visual Studio 2005


 


Una de las maneras de poder crear este tipo de objeto es mediante Visual Studio 2005, para ello debemos generar un nuevo proyecto del tipo “Database” ya sea en C# o VB.NET.


 




Al realizar esta operación nuestro segundo paso en el asistente es indicar a que servidor de SQL2005 nos vamos a conectar


 




Si nuestro servidor no se encuentra en la lista, debemos agregarlo desde el botón “Add New Reference..”


Nuestro siguiente paso es agregar un componente a nuestra solución desde el “Solution Explorer”


 




Como podemos observar se pueden agregar Stores Procedures, User Defined Function, User Defined type, Trigger, Aggregate y Class. En nuestro caso usaremos “User Defined Type”. Cabe mencionar que dentro de una solución usted podría tener mas un ítem del tipo que fuere.


Al realizar esta operación el Visual Studio nos genera la estructura necesaria para este objeto, en la siguiente figura se muestra un fragmento del código.


 


using System;


using System.Data;


using System.Data.SqlClient;


using System.Data.SqlTypes;


using Microsoft.SqlServer.Server;


 


[Serializable]


[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]


public struct udttime : INullable


{


    public override string ToString()


    {


        // Replace the following code with your code


        return “”;


    }


…………


 


Ahora empezaremos modificando el código base para poder llegar a nuestro objetivo final.


En principio le indicaremos una nueva propiedad “IsByteOrdered” a valor True para que el servidor utilice comparaciones ordenadas por Bytes.


 


[Serializable]


[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,IsByteOrdered = true)]


 


Nuestro siguiente paso es crear el código de estructura para nuestro tipo de datos UDTTIME.


 


public struct UDTTIME : INullable


{


    private int milliseconds;


 


    private bool m_Null;


 


    public static UDTTIME Parse(SqlString s)


    {


        if (s.IsNull)


            return Null;


 


        UDTTIME  x = new  UDTTIME();


        TimeSpan ts = TimeSpan.Parse((string)s);


        x.milliseconds = (int)ts.TotalMilliseconds;


 


        return x;


    }


   


    public override string ToString()…………


 


Aquí estamos usando el tipo de datos TimeSpan y trabajando los tiempos en milisegundos


Ahora lo que haremos es implementar el método ToString con el siguiente código:


 


public override string ToString()


 {


  return 


  TimeSpan.FromMilliseconds(this.milliseconds).ToString();


 }


 


Este método es de suma importancia ya que nos convertirá el valor del tipo timeSpan a algo legible por nuestros usuarios J


 


Una de las cosas que se pueden hacer también dentro de un tipo de datos es definir funciones, imaginemos que ahora queremos tener dentro de este tipo de datos una función que nos permita a un valor Time X sumarle tantos milisegundos. Para poder realizar esto agregaremos el siguiente código


 


 


 


 


 


public UDTTIME Addtime(UDTTIME o)


    {


        if (o.IsNull)


            return Null;


 


        else


        {


            this.milliseconds += o.milliseconds;


            return this;


        }


    }


 


Ahora debemos implementar el tratado de los tipos Null para ello implementaremos lo siguiente.


 


public bool IsNull


    {


        get


        {


            // Put your code here


            return m_Null;


        }


    }


    public static UDTTIME Null


    {


        get


        {


            UDTTIME h = new UDTTIME();


            h.m_Null = true;


            return h;


       }


    }


 


Ahora ya estamos en condiciones de poder hacer el deploy de este componente. El código completo ha quedado de la siguiente manera:


 


using System.Data.SqlClient;


using System.Data.SqlTypes;


using Microsoft.SqlServer.Server;


 


[Serializable]


[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,IsByteOrdered = true)]


public struct UDTTIME : INullable


{


    //  milliseconds


    private int milliseconds;


 


    // Private member


    private bool m_Null;


 


    public static UDTTIME Parse(SqlString s)


    {


        if (s.IsNull)


            return Null;


 


        UDTTIME  x = new  UDTTIME();


        TimeSpan ts = TimeSpan.Parse((string)s);


        x.milliseconds = (int)ts.TotalMilliseconds;


 


        return x;


    }


    public override string ToString()


    {


       return TimeSpan.FromMilliseconds(this.milliseconds).ToString();


    }


    public UDTTIME Addtime(UDTTIME o)


    {


        if (o.IsNull)


            return Null;


 


        else


        {


            this.milliseconds += o.milliseconds;


            return this;


        }


    }


    public bool IsNull


    {


        get


        {


            // Put your code here


            return m_Null;


        }


    }


    public static UDTTIME Null


    {


        get


        {


            UDTTIME h = new UDTTIME();


            h.m_Null = true;


            return h;


       }


    }


}


 


Ahora desde Visual Studio haremos el deploy hacia el servidor que nos habíamos conectado, para ello debemos ir al solution Explorer y hacer el Deploy pulsando el botón alterno del Mouse sobre el nombre de la solución.


 


Luego de hacer el deploy (solo demorara unos segundos) entraremos al Management Studio en el cual realizaremos las pruebas con nuestro nuevo tipo de dato.


 


Primero crearemos una tabla con nuestro nuevo tipo de datos


 


USE ADVENTUREWORKS


GO


 


CREATE TABLE TIMES


(


  id int,


  [htime] UDTTIME NULL


)


GO


 


Luego insertaremos algunos valores


 


INSERT TIMES VALUES (1, ’00:01:20′)


INSERT TIMES VALUES (3, ’16:30′)


GO


 


Y por ultimo veremos como han quedado en nuestra tabla, aquí usaremos el ToString para que el resultado sea legible para un usuario


 


SELECT Id, HTIME.ToString() AS TIME


FROM TIMES


GO


 


Ahora en nuestra siguiente prueba trataremos de usar una suma de milisegundos a una hora determinada


 


DECLARE @Hours1 UDTTIME


SET @Hours1 = ’10:00′


DECLARE @Seconds UDTTIME


SET @Seconds = ’00:00:10′


SET @Hours1 =


   @Hours1.Addtime(@Seconds)


SELECT @Hours1.ToString()


 


Ya disponemos de nuestro tipo de datos Hora que SQLServer por default no lo trae J.


Se podrían seguir agregando métodos al mismo como por ej.: Restar horas, tener un método para indicar el total de horas que representa un time, etc.


 


Cabe mencionar que cuando hemos hecho el Deploy de nuestro objeto SQLServer lo introduce dentro de la base de datos con lo cual si se hace un Backup / Restore se mantendrán todos los Assemblies.


 


 


Hacer el deploy sin disponer de Visual Studio 2005


 


No es una condición disponer de Visual Studio para poder hacer objetos CLR dentro de SQL2005, de hecho con un editor de textos simples y desde líneas de comando se puede resolver. En esta sección veremos los pasos necesarios para hacer este deploy sin el uso de visual Studio, tomaremos el código completo que hemos generado anteriormente y lo transformaremos en una dll con el SDK de .NET, para ello necesitaremos ejecutar el siguiente comando desde la línea de comandos


 


csc /t:library udttime.cs


 


Ahora debemos acceder a nuestro Management Studio.


Para no generar confusión con lo anteriormente realizado crearemos una nueva base de datos.


 


USE MASTER


GO


 


CREATE DATABASE TIME1


GO


 


Nuestro siguiente paso será crear el Assembly en nuestra nueva base de datos, para ello usaremos nuevas sentencias de TSQL


 


USE TIME1


GO


 


CREATE ASSEMBLY UDTTIME


FROM ‘C:\UDTTIME.dll’


GO


 


Continuaremos creando el tipo de datos indicándole que el origen es un assembly


 


CREATE TYPE [dbo].[UDTTIME]


EXTERNAL NAME [UDTTIME].[UDTTIME]


GO


 


Nota: No confundir la palabra EXTERNAL con que la .dll este dentro o fuera del motor, siempre estará dentro y ese paso se realizo cuando hemos ejecutado el “CREATE ASSEMBLY”, el External en este caso (al igual que cuando creamos un Store Procedure , User Define Function, Aggregate Function o Trigger) indica que el código de ese objeto es un assembly y no código TSQL


 


Por ultimo paso nos quedaría probar el tipo de datos UDTTIME, para lo cual ejecutaremos el siguiente código:


 


DECLARE @TIME1 UDTTIME


SET @TIME1 = ’20:50:00′


SELECT @TIME1.ToString()


 


Conclusiones finales:


 


La inclusión del CLR dentro del motor de base de datos ha generado muchas discusiones entre los distintos especialistas, sin ninguna duda que es una feature muy importante pero hay que ser cuidadoso en como se la utiliza. Siempre es recomendado realizar con TSQL y solo dejar para CLR aquellos tipos de objetos que no se pueden crear con TSQL (como por ej. el que vimos en este articulo) o para aquellas operaciones donde el procesamiento de calculo pueda ser un problema resolver con este ultimo.