Entropía en la comunicación de las organizaciones

Entropía… cuando escuche esta palabra la semana pasada no se me venia nada a la cabeza (obvio no he sido muy amante de la física ni menos de la termodinámica) pero cuando lo mencionaron relacionado a las organizaciones fue cuando me di cuenta que necesitaba informarme un poco mas del tema. Gran problema encontré al no tener una definición clara y sencilla de esto en internet, por eso espero que este post sea lo suficientemente claro y sencillo para que se pueda entender.

Supongamos que eres dueño de una empresa y a pesar del pasos de los años no cambias ni de estrategia y sigues operando de la misma forma que hace 20 años, y con el tiempo quiebras. Por otro lado supón que estas en la segunda guerra mundial y necesitas pasar una información muy importante a tu base, pero no estas en el radio suficiente de recepción y envío, y eso hace que llegue la información un poco distorsionada a tu base llegando incompleta la información.

¿Que sucedió? La evolución espontánea de un sistema aislado se traduce en un incremento en la entropía. En el primero caso la empresa se mantuvo como un “sistema aislado”, se mantuvo al margen y no hizo ni un cambio en su estrategia, por ende con el tiempo quebró, esto significa para nuestro caso de estudio que su entropía subió y hasta un nivel máximo. En el segundo caso tenemos que en el sistema de comunicación (emisor – mensaje – receptor) existió “ruido” o algún disturbio que no permitió que la comunicación fluya correctamente, a esto se le llama entropía y mientras mayor sea el problema de comunicación mayor será la entropía.

La entropía puede ser aplicado en muchos aspectos, por ejemplo en las organizaciones mide el caos o la desorganización y en la información mide la incertidumbre de la fuente (gracias a Shannon podemos saber cuantos bits necesitas para codificar una cantidad de información de acuerdo a su probabilidad, y estar seguros que con menos bits perderías información).

¿Y cual podría ser la solución para obtener una menor entropía? éste involucra un proceso de cambio, no necesariamente son sistemas aislados, podría interactuar con otros sistemas para corregir este desorden, ruido o lo que interfiera.

En el primer caso involucraría un proceso de cambio de pasar de desorganización a organización, de caos a orden, para esto necesitaremos hacer muchas cosas como por ejemplo: Estar preparados para los cambios, mantener organizaciones flexibles (gran problema de esto es que la mayoría son rígidas), estar conscientes de la entropía, tener personal capacitado, tener objetivos claros, saber para donde vamos, etc.

En el segundo caso (y tema central de este post) cambian un poco las cosas, porque si bien la comunicación puede tener “interferencias” por temas de infraestructura también puede fallar por mal entendimiento.

¿Que sucede si hay entropía en la comunicación en las organizaciones? pues la información se degrada en cuanto a su valor, realmente perdería su razón de ser y hasta podría hacernos tomar una decisión equivocada.

¿Que podríamos hacer? pues básicamente 2 cosas, primero apoyarnos en herramientas de TI que puedan soportar temas de comunicación en nuestras organizaciones y segundo, a pesar de hablar español, pues entendernos y estandarizarnos en la comunicación.

Hace unos años tuve la oportunidad de participar en un proyecto que involucraba a varios países, el corporativo se encontraba en Europa y nosotros formábamos parte de Latinoamérica (habían otros de Estados Unidos y Asia), a pesar de que todos nos comunicábamos en ingles, teníamos grandes problemas de entendimiento, suena increíble porque para una empresa multinacional su infraestructura es lo primordial, pero no solo se necesita tecnología para poder disminuir la entropía en las comunicaciones, en este caso tuvimos problemas por la estructura rígida de la organización, no podíamos comunicarnos con los que realmente participaban del proyecto sino con los encargados de cada país y estos no tenían el conocimiento total técnico y/o funcional, lamentablemente esto sigue perdurando y si no hay un cambio al respecto la entropía tendera a subir.

Finalmente la entropía esta siempre, dependerá de nosotros o de nuestra organización manejar el nivel que se deba tener, mientras menor sea es mejor será.

Audit SQL2008 + Change Data Capture (CDC) + ASP.NET + WCF + Silverlight 3

Alguna vez les han pedido los usuarios que querían saber quien modificó que dato y que día lo hizo?, cuales fueron los datos anteriores?, etc. Y tenían una aplicación web que tenia una autenticación vía Forms (que autenticaba por active directory un usuario windows) y usaba Silverlight, Ajax, ASPXs y Servicios (WCF + Silverlight) y el windows principal tenia que pasar por todas esas capas???? pues esa es mi historia :(

como empezó? pues primero no quería programar o al menos quería tener lo mínimo de programación y la mayor performance (mi sueño de programador :p) ….

Viendo las nuevas características que aparecieron con SQL2008 me tope con la auditoria (una forma de hacer trace), y eso porque estaba buscando una forma de saber quien modifico que dato y como estuvo antes de la modificación, además de las inserciones y modificaciones. La idea era evitar los TRIGGERS!!!:

Resultado Final que necesitaba tener:

Usuario 1 — Inserción tabla X1 — Datos(d1,d2,d3…)
Usuario 2 — Actualización tabla X1 — DatosIniciales(d1,d2,d3…)  DatosFinales(d1,d2,d3…)
… etc.

Parte I

Primero di alta mi Audit en SQL2008 (a nivel servidor)  (Audit es una nueva característica de SQL 2008 y me permite capturar eventos del servidor y almacenarlos en un archivo, log de windows, etc –> lo puedes revisar aquí ):

use master
go
CREATE SERVER
AUDIT [ServerAudit]
TO FILE
( FILEPATH = ‘C:’
,MAXSIZE = 100 MB
,MAX_ROLLOVER_FILES = 2147483647
,RESERVE_DISK_SPACE = OFF
)WITH

(QUEUE_DELAY = 2000
,ON_FAILURE = CONTINUE)

go

ALTER SERVER AUDIT [ServerAudit] WITH(STATE=ON)

Luego tuve que configurar el conjunto de acciones que necesitaba capturar, y por cada una de las tablas:

go
use
MyBase
go
CREATE DATABASE AUDIT SPECIFICATION BDAudit
FOR SERVER AUDIT[ServerAudit]
ADD (INSERT , UPDATE, DELETE ON dbo.tabla1 BY PUBLIC)
,ADD (INSERT , UPDATE, DELETE ON dbo.tabla2 BY PUBLIC)         
,ADD (INSERT , UPDATE, DELETE ON dbo.tabla3 BY PUBLIC)         
WITH (STATE = ON)

Con esto pensaba que ya tenia todo listo y preparado para auditar mi BD, pero no contaba con que el audit no almacena los DATOS que se están modificando. No me crees?? (yo no me creería si lo leyera :p) así que prueba creando un stored procedure que grabe en una tabla y ejecútalo y mira si te almaceno los datos que insertaste.

para ver la información basta con ejecutar esto:

select * from fn_get_audit_file(‘C:*’, default, default)

Audit

Conclusión de Parte I: Ya pude capturar los eventos ejecutados en la BD, y sin programar :) , además de la hora que se realiza y el usuario que lo ejecuta, el problema es que no me dice cuales son los datos que cambiaron.

Parte II

Seguí revisando en las características de SQL2008 y me encontré con un tema interesante: Change Data Capture (CDC), esto es realmente genial, porque internamente SQL crea tablas alternas a las reales y graba la información que va cambiando y lo mejor de todo es que es ASINCRONO, esto lo hace ser mas rápido.

para esto ejecutamos el siguiente script:

use MyBase
go
–habilitamos el cdc
exec sys.sp_cdc_enable_db
go
–Agregamos las tablas a auditar
EXEC sys.sp_cdc_enable_table ‘dbo’, ‘tabla1’, @role_name = NULL,@supports_net_changes =1,@captured_column_list = ‘campo1, campo2, campo3’;

Con esto habremos habilitado el cdc para la tabla “tabla1” y crea automáticamente las siguientes tablas:

cdc_tablas

 

Y en la tabla que termina en CT, podremos encontrar los datos que se han modificado. Tomar nota que el CDC crea 2 Jobs, uno que se estará ejecutando continuamente y otro que se ejecutara una vez al día para eliminar los registros (puedes cambiar el horario del job), como los elimina seria bueno que los almacenaran en otra tabla si es que fuera necesario tener un histórico de los cambios.

El problema con esto es que no almacena el usuario con el cual se hizo el cambio, solo almacena lo datos, por ello debemos combinar esta parte con la anterior, en el audit tengo el nombre del objeto, la hora (SYSUTCDATETIME()) y con ello podemos hacer el join con esta tabla y generar una auditoria mas robusta.

Una vez que termine esto pensé que ya tenia solucionado todo, pero me equivoque porque lo solucione de la parte de la BD pero no de la aplicación.

Conclusión de la Parte II: Ya puedo capturar cualquier evento transaccional en mi BD con los datos que necesito y sin haber programado muchas cosas. El problema ahora será mandar a la BD el usuario correcto. (Con autenticación Windows)

 

Parte III

Tenia una aplicación web que su medio de autenticación era Forms con la siguiente configuración:

<identity impersonate=”true/>

<authorization>
            <deny users=”?/>
        </authorization>
        <authentication mode=”Forms>
            <forms name=”.ASPXAUTHloginUrl=”~/SecurityLoginPage.aspxprotection=”Validationtimeout=”999999“/>
        </authentication>
        <membership defaultProvider=”SecurityMembershipProvideruserIsOnlineTimeWindow=”15“>
            <providers>
… y todo lo demás

La clase SecurityMembershipProvider me validaba el login con el Active Directory, le pasaba el token para que lo validara y dejara entrar al usuario. (es un ambiente intranet)

Para poder grabar el usuario en los casos anteriores debía de tener una conexión integrada con el usuario de Windows es decir:

<add name=”tmpConnectionStringconnectionString=”Data Source=MyServer;Initial Catalog=MyBase;Integrated Security=true;providerName=”System.Data.SqlClient“/>

Pero como la autenticación era vía Forms el usuario que iba a BD era el usuario de la maquina y no el usuario que valido el Active directory en mi pagina de login.

Significa que cualquier cambio en la paginas de Ajax y ASPXs capturaba el usuario de la maquina (realmente el que pasaba el usuario era el explorador de internet), para ello tuve que cambiar la identidad y el Windows principal del hilo de la aplicación con el siguiente código:

 

internal class BLSecurityPrincipal : IPrincipal
    {
       IIdentity m_User;
       IPrincipal m_OldPrincipal;
       static bool m_ThreadPolicySet = false;

       BLSecurityPrincipal(IIdentity user)
       {
          m_OldPrincipal = Thread.CurrentPrincipal;         
          m_User = user;         
          Thread.CurrentPrincipal = this;
       }

       static public void Attach(IIdentity user)
       {
           Attach(user, false);
       }

       static public void Attach(IIdentity user, bool cacheRoles)
       { 
          IPrincipal customPrincipal = new BLSecurityPrincipal(user);

          if(m_ThreadPolicySet == false)
          {
             AppDomain currentDomain = AppDomain.CurrentDomain;
             currentDomain.SetThreadPrincipal(customPrincipal);
             m_ThreadPolicySet = true;
          }         

       }

       public void Detach()
       {
          Thread.CurrentPrincipal = m_OldPrincipal;
       }

       public IIdentity Identity
       {
          get { return m_User; }
       }

       bool IPrincipal.IsInRole(string role)
       {
           throw new NotImplementedException();
       }

    }

Con el código de arriba sobrescribo el User.Identity que se tenga en la aplicación. Pero no es suficiente para que la conexión a la BD tome ese usuario, porque es necesario también reemplazar el System.Security.Principal.WindowsIdentity de la aplicación. Para poder solucionar este tema puse el siguiente código:

    internal class BLWindowsImpersonate
    {
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_PROVIDER_DEFAULT = 0;

        WindowsImpersonationContext impersonationContext;

        [DllImport(“advapi32.dll“)]
        public static extern int LogonUserA(String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);
        [DllImport(“advapi32.dll“, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DuplicateToken(IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport(“advapi32.dll“, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();

        [DllImport(“kernel32.dll“, CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        public bool impersonateValidUser(String userName, String domain, String password)
        {
            WindowsIdentity tempWindowsIdentity;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            if (RevertToSelf())
            {
                if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {
                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                        impersonationContext = tempWindowsIdentity.Impersonate();
                        if (impersonationContext != null)
                        {
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                            return true;
                        }
                    }
                }
            }
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (tokenDuplicate != IntPtr.Zero)
                CloseHandle(tokenDuplicate);
            return false;
        }

        public void undoImpersonation()
        {
            impersonationContext.Undo();
        }

    }

Con esto ya podía suplantar el usuario que me daba el browser por el usuario que entro a la aplicación, es decir si abría un explorador de internet en una maquina X y tenia 10 usuarios entrando en distinto tiempo a la aplicación desde esa maquina no podía identificarlos (solo podía identificar al usuario que se había logeado en la maquina), pero con este código ya puedo identificar a los usuario uno por uno.

Conclusión de la Parte III: Ya puedo identificar al usuario que se loguea y mandarlo a SQL para que haga su trabajo (mas bien que haga lo que le configure en los primeros pasos), con esto pensé que ya había terminado pero no fue así :( … no funciona para mis paginas de Silverlight.

 

Parte IV

Lo que parecía que iba a salir fácil, se complicó, la razón: Silverlight + WCF, el problema es que no se puede pasar la identidad a la aplicación de Silverlight, NO SE PUEDE, pueden verificarlo acá: http://msdn.microsoft.com/en-us/library/dd744835(VS.95).aspx

Específicamente en esta parte:

The Silverlight client-side ServiceReferences.ClientConfig configuration file (that is generated by the Add Service Reference tool or by using the Service Model Proxy Generation Tool (SLsvcutil.exe) for SOAP services that use Windows authentication) may specify the TransportCredentialOnly security mode. However, in Silverlight 3, this mode is exactly equivalent to the None security mode. In both modes, Windows credentials are managed by the browser and are not under your application’s control.

El problema es un poco mas grande, porque a parte de no poder tener la credencial en la aplicación de Silverlight, no se lo puedo pasar a mis servicios.

Y bueno hoy después de muchos apuros por fin termine de hacerlo, se que no es una solución optima, pero al menos salí del apuro, de todas maneras me avisan si por ahi uds tienen algo mejor.

Mi solución fue pasar por parámetros a Silverlight el usuario y password (Encriptado por supuesto) y pasarlo como parámetro a mi servicio, e impersonar mi cnx a la BD con ese usuario, o sea, un poco mas despacio:

Primero en Silverlight pasamos los parámetros:

silver

Segundo en el App.xaml.cs

if (e.InitParams[“userName“]!=null)
         UserName = e.InitParams[“userName“];

if (e.InitParams[“ClaveID“] != null)
         ClaveID = e.InitParams[“ClaveID“];

 

Tercero al método de Inserción u modificación le agrego los métodos de usuario y password. Y utilizo mi método de Impersonalizacion del Windows Principal.

service

 

Con esto ya tengo funcionando la captura de usuarios, eventos, datos modificados (el antes y después) y con un poco de código (hubiera esperado que no haya código…)

Aca les paso algunos recursos interesantes:

Audit SQl 2008 –> http://msdn.microsoft.com/en-us/library/dd392015.aspx
CDC –> http://www.databasejournal.com/features/mssql/article.php/3720361/Microsoft-SQL-Server-2008—-Change-Data-Capture–Part-I.htm  y  http://www.kodyaz.com/articles/change-data-capture.aspx
Porque no se puede obtener el usuario con el Change Data Capture? –> https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=299164&wa=wsignin1.0

LN + MDX + ExcelMDX + SQL 2008

Mas que un post esto será una recopilación de otros post. Básicamente porque me fue un poco difícil saber que pasaba con mi Analisys Services en base a un problema inicial.

Problema Inicial:
Necesito hacer una agregación de productos de una medida de mi cubo, como saben la agregación por defecto que existe en SSAS es suma, pero no hay uno de producto.

Es decir necesitaba: a*b*c*d*….

Solución:
Como es un problema que ya han tenido muchas personas, la solución lo encontré en codeplex, que al final te redirecciona a esta pagina –> http://geekswithblogs.net/darrengosbell/archive/2006/07/18/85539.aspx 

básicamente la formula se resume en EXP(sum(logN(col_with_vals))) y ya lo puedes pasar a MDX y funciona…

Nota a parte tiene Mosha Pasumansky (para mi uno de los mejores en MDX) con una alternativa mucho mas interesante –> http://sqlblog.com/blogs/mosha/archive/2006/12/18/how-to-aggregate-values-as-a-product-multiplication-in-mdx.aspx

que ya no utiliza Logaritmo Neperiano sino un Logaritmo base 10 –>

with
member Measures.Weight as [Organization].[Organizations].unary_operator
member Measures.WeightLog as log10(Measures.Weight)
member Measures.SumOfWeightLogs as Sum(Descendants([Organization].[Organizations].CurrentMember,,Leaves), Measures.WeightLog)
member Measures.ProductOfWeights as 10^Measures.SumOfWeightLogs

select {Measures.ProductOfWeights} on 0
from [Adventure Works]

Hasta ahí no hay problemas para poder implementar la solución, pero por cosas de la vida no me funciono en el servidor, no funciono ninguna de las soluciones!!!

La Salvación: 
Cuando busque por todos lados porque había pasado esto me entere de cosas que no sabia hasta hoy de SSAS, para empezar las librerías que están por defecto referenciados en el server de AS.

VBAMDX –> Esta librería es la que nos permite utilizar todas las funciones de VBA en nuestro MDX y adivinen!!! tiene la función LOG (de logaritmo)

ExcelMDX –> Nos permite utilizar librerías de Excel en el MDX como el mutifamoso IRR (TIR en español, que es la tasa interna de retorno, otro problema que les contare en otro post), acá tenemos la función LN, LOG10, etc…

Ahora los problemas que podemos tener cuando no nos funciona la consulta de MDX expuesta en la solucion es porque no estan registradas.

Para el VBAMDX basta con revisar el Source y la ruta y la dll referenciada. Si no lo esta lo debemos registrar manualmente, click derecho –> NEW ASSEMBLY –> etc… la dll que debes tener debe ser (C:Program FilesMicrosoft SQL ServerMSAS10.MSSQLSERVEROLAPbinmsmdvbanet.dll)

Como mi problema ha sido con las funciones de Excel dentro de mi MDX, el problema era la dll: ExcelMDX, sencillamente porque en mi servidor tenia excel 2003 y le hice el upgrade a excel 2007 y esto se debe hacer antes de instalar SQL 2008, por ello se debe reparar el SQL para solucionarlo.

Ahora se preguntaran porque instale excel en el server, la respuesta es que sql no viene con la dll de excel para utilizar esas funciones, asi que si la vas a usar te obliga a tener excel es un bug registrado en microsoft –> https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=124864

Otro detalle que deben saber es que LOG es una palabra reservada asi que si la deseas utilizar por VBA debes colocarlo asi: VBA![LOG] para no tener problemas.

Resumen:
Lo aprendido hoy es que podemos utilizar las funciones de Excel en MDX pero necesitamos instalarlo en el server, y la instalacion del excel debe ser antes del de SQL, sino tendras que reparar el SQL como lo hice yo :)

R Project for Statistical Computing + .net + BI

Que pasa cuando tenemos que agregar lógica matemática a nuestros proyectos? especialmente de BI? pues muchas veces vamos por ayuda a MatLab, pero cuando a veces nos damos cuenta del costo preferimos ir por algún software libre, como es el caso de R (http://www.r-project.org/), éste un potente motor que nos puede ayudar a hacer muchas operaciones matemáticas financieras, el objetivo de este post no es explicar las formulas matemáticas expuestas en R, sino ver como podemos colocarlo en nuestra solución.

Para empezar debes descargar la versión de R de la pagina oficial. Luego debemos descargar un conector R COM+ (RSrv250_pl1.exe –> http://sunsite.univie.ac.at/rcom/download/current/RSrv250_pl1.exe), que expone a R como un conjunto de objetos para poder programarlo (y acá va todo el floro de lo que es COM+ y como se puede utilizar en .net).

He tenido mucho pasado en .net y eso me ha ayudado a poder extender funcionalidades en Reporting Services, Integration Services y etcs…. y eso me ha ayudado a agregar R en el proyecto de BI.

Bueno ahora si a código!!!, si eres primerizo en esto primero debes entrar a este link –> http://www.codeproject.com/KB/cs/RtoCSharp.aspx, se puede ver como se utiliza R con un ejemplo sencillo en .net

Si ya estas en algo con todo esto debes entrar a ejemplos mas avanzado -> http://joachimvandenbogaert.wordpress.com/2009/03/26/r-and-c-on-windows/ ;http://joachimvandenbogaert.wordpress.com/2009/02/20/rcom-and-c-safearraytypemismatchexception/

Ya una vez que estas con ese nivel pues llegas a este párrafo :p jejejeje, la realidad te dice que no tienes tiempo de programar dos veces, una en R y otro en .net para que se acople, entonces la idea seria tener un generador que lee archivos en R sea cual fuera lo que hace y te devuelva un resultado y finalmente eso es lo que es:

public object EjecutarR(DataTable datos, string rutaR)
{
  object o1 = null;
  if (datos.Rows.Count > 1)
   {
    try
     {
      StatConnector sc1 = new StatConnectorClass();
       sc1.Init(“R”);

        StringBuilder valoresFilas;
        StringBuilder valoresColumnas = new StringBuilder();
        //Llenar Datos
        int i, j;
        for (i = 0; i < datos.Columns.Count; i++)
        {
         valoresFilas = new StringBuilder();

         for (j = 0; j < datos.Rows.Count; j++)
         {
          if (datos.Columns[i].DataType.Name == “String”)
           valoresFilas.Append(“””);
          if (datos.Rows[j][i].GetType() == Type.GetType(“System.DBNull”))
           valoresFilas.Append(“0”);
          else
           valoresFilas.Append(datos.Rows[j][i].ToString());
          if (datos.Columns[i].DataType.Name == “String”)
           valoresFilas.Append(“””);
           valoresFilas.Append(“,”);
          }

          sc1.EvaluateNoReturn(datos.Columns[i].ColumnName + ” <- c(” +
          valoresFilas.ToString().Substring(0, valoresFilas.ToString().Length – 1) + “)”);

          valoresColumnas.Append(datos.Columns[i].ColumnName);
          valoresColumnas.Append(“,”);
         }

         sc1.EvaluateNoReturn(“dat <- data.frame(” +
         valoresColumnas.ToString().Substring(0, valoresColumnas.ToString().Length – 1) + “)”);

         sc1.SetSymbol(“archivo”, rutaR);

         sc1.EvaluateNoReturn(“source(archivo)”);
         o1 = sc1.GetSymbol(“Resultados”);
         sc1.Close();
         Utilitarios.Funciones.NAR(sc1);
         GC.Collect();
         GC.WaitForPendingFinalizers();
         }
         catch (Exception ex)
         {
          if (ExceptionPolicy.HandleException(ex, ErrPolicy.Business))
           throw;
          }
         }

 

El código que se encuentra en otro color indica lo que utilizamos de R. Para explicarlo un poco, les cuento que este código me permite en base a un datatable meter cualquier valor a R, y que lo lea como una matriz (en realidad lleno vectores y creo un dataframe con esos), con ese input llamo a R y leo un archivo (que lo paso por parámetro) en ese archivo se tiene el algoritmo de R y dicho algoritmo debe asignar a la variable Resultado lo que necesito traer a .net

Este script me permite leer cualquier archivo de R sin necesidad de cambiar una línea de código, me permite meter cualquier valor de .net (siempre y cuando este en un datatable) y leerlo en R.

Otra solución seria llamar por ODBC a SQL desde R pero no esa opción desde el punto de vista de arquitectura no me agrada. Es mejor que pase por tu capa de datos (Entity Framework)

Este codigo lo colocamos en un servicio .net y lo podemos llamar desde Integration Services 2008 (que ya permite tener referencias web) y con esto podemos poblar cubos, o transformar datos.

Espero lo hayan entendido :)

SQL 2005 –> SQL 2008: Lo que debo tener en cuenta en mi próxima migración

Una semana muy entretenida que termino con una cereza en el pastel… una migración que no fue tan sencillo como me fue de SQL 200 a 2005. A veces sentimos que planificamos todo realmente bien (técnicamente hablando), pero no siempre tenemos buenos resultados, a raíz de esto, con los temas ya solucionados, decidí escribir mi experiencia en esta migración.

La migración que lleve a cabo incluía a las Base de Datos que estaban en SQL 2005, paquetes de Integration Services 2005 y reportes en Reporting Services 2005, en cuanto a Analisys Services ya no tuve que hacerlo porque el proyecto ya lo tengo en la nueva versión (ya no tan nueva que digamos).

1.- Base de Datos

Como ya lo hemos visto en versiones anteriores SQL2008 también tiene una herramienta que da un “check” a nuestra configuración y componentes necesarios (tanto hardware como software)

check Upgrade

 

El System Configuration Checker identifica los componentes instalados y el hardware que tenemos.

El install Upgrade Advisor te instala un programita que te ayudara a verificar las compatibilidades de tu BD para ser el upgrade a 2008

image

 

y con un sencillo wizard te ayuda a identificar los posibles problemas en tu migración, lo bueno de esta herramienta es que te analiza todos los componentes de SQL no solo la BD sino también reportes, paquetes de SSIS, hasta DTS de la versión 2000 y por supuesto proyectos de Analisys Services de versiones anteriores. FInalmente me manda un reporte como este:

image

Y como buen apurado que soy no me di cuenta de un warning muy importa del cambio de la versión del SQLClient, que en la parte de SSIS les explicare el gran problema que tuve. (por cierto también me recomendó el usar las nuevas capacidad de SSIS en cuanto a lookup que seguro en otro post lo explicaré.), también me menciona casos del full text index, de los cambios realizados, pero como deje de usar esa característica, lo deje :)

si desean mas datos (realmente es sencillo el uso) aca les dejo unos links:

Bueno una vez que vemos que en la BD no hay mas problemas, entonces vamos al siguiente paso que es un poco mas interesante SSIS.

2.- Integration Services

En esta parte realmente el problema no fue en la instalación, sino en hacer que mis paquetes hechos en SQL2005 funcionen. Como vimos en el Upgrade Advisor ya debí de haberme dado cuenta que tenia un problema con la versión del SQLCliente para mis conexiones OLEDB de mis paquetes, pero no fue el único problema.

Una vez hecho el upgrade y queriendo ejecutar un paquete (ya convertido a SSIS 2008) me mostró el siguiente error: (la ejecución fue “dtexec.exe /f D:JOGASyncPrices.dtsx /CONFIGFILE D:JOGAnewConfigBase.dtsConfig”)

Error: 2009-07-12 16:33:11.44
Code: 0xC001700A
Source:  
Description: The version number in the package is not valid. The version number cannot be greater than current version number.
End Error

Busque solucionar este error de muchas formas, pensando que era el paquete el problema, analizando el xml, los archivos de configuración etc etc etc… y gracias a este foro –> http://social.msdn.microsoft.com/Forums/en-US/sqlintegrationservices/thread/744957ad-038a-46ba-aa70-0adab03a5f4d/ me indica que el problema es el DTEXEC, como deseo que se ejecute con el DTEXEC de SSIS 2008 debo colocar su ruta completa es decir: “C:Program FilesMicrosoft SQL Server100DTSBinndtexec.exe /f D:JOGASyncPrices.dtsx /CONFIGFILE D:JOGAnewConfigBase.dtsConfig”. Con ese pequeño cambio las cosas mejoraron pero no se solucionaron por completo, porque a la siguiente ejecucion me salio un warning que al inicio no le hacia caso pero era el culpable de que nos e ejecutara mis paquetes este fue:

Warning: 2009-07-12 16:30:29.55
Code: 0x80012011
Source: SynPrices 
Description: Cannot load the XML configuration file. The XML configuration file may be malformed or not valid.
End Warning

Como verán se ejecutaba mi paquete pero no se leía mi archivo de configuración, en el cual tengo mis conexiones a servidores de producción, entonces se ejecutaba el paquete y se cargaba todo en mi ambiente de pruebas. Esto si fue un poco mas tardado encontrar la solución, aplique la filosofía de mi master: “divide y vencerás” :p .. es decir deshice mi paquete, para que no se vea tan complejo y probar parte por parte y encontré el problema, era el archivo de configuración.

Resulta que en la versión anterior yo tenia un archivo de configuración para todos mis paquetes, en este archivo de configuración colocaba todas mis conexiones, y aunque no lo usara en el paquete funcionaba, pues en SSIS 2008 ya no funciona igual, si hay alguna conexión que no estas utilizando en el paquete (es decir que no este en el connection managers del paquete) te sale muestra ese warning. Entonces empecé a crear archivos de configuración para cada paquete (realmente generalice unos cuantos, ya que varios paquetes usaban las mismas conexiones) y con eso lo solucione.

Finalmente lo ultimo es cambiar el provider de SQL Native Client a SQL Server Native Client 10.0, con estos cambios ya empieza a funcionar todo normalmente, seguro esta semana estaré viendo algunas consecuencias de mi migración de SSIS y les estaré comentando. (con mi cnx de .net Providers no tuve ningún problema :p)

aca unos links de interes:

3.- Reporting Services

Con el upgrade a 2008, realmente no tuve grandes problemas, mis reportes funcionaron a no ser que tuve que hacer algunos arreglos en mi IIS.

Como sabrán con SQL2008 ya no es necesario tener IIS instalado en el server para utilizar SSRS, y en el upgrade lo que hizo automáticamente es habilitar el puerto 8081 para mis reportes (antes se encontraban en el puerto por defecto del IIS 8080).

Debes agregar los permisos necesarios y las credenciales necesarios, para no repetir todo esto seguimos el Upgrade WorkFlow que nos proporciona la documentación de Microsoft –> http://technet.microsoft.com/en-us/library/ms143747.aspx 

Fuera de esto el problema viene con los reportes que desarrollamos en SSRS2005, que es motivo para un post completo. En una próxima edición :p

Y con todo esto hoy día puedo decir que por fin funciono lo que tenia que funcionar :p

Espero les ayude en algo la experiencia que tuve :) .. hasta la próxima

Programatic access to the Microsoft Office Visual…

Bueno, el post de hoy no es necesariamente de los temas que quisiera hablar, pero dada las circunstancias y el tiempo que me tomo encontrar la solución, quería compartir con uds. esto por si tienen el mismo problema.

Como saben estoy tratando de combinar tecnologías de Microsoft en mis soluciones, y ahora me toco meter a VSTO con vs2008 (porque recién tuve un requerimiento que tenia que ver con Excel directamente) y me tope con mi primer problema:

“Programatic access to the Microsoft Office Visual Basic for Applications project System could not be enabled”.

como bien lo dice el titulo (lo puse agrede para quienes lo busquen :p)
error1

Como sabrán también no me gusta mucho solucionar el tema por solucionar, siempre me gusta saber el porque.. y esa es la razón de este post…

Para empezar debemos tener en cuenta que Office esta construido en base a las tecnologías que Microsoft saco con COM+, es decir no es administrado (no .net), para que funcione VSTO el framework se comunica con los componentes de Office (en mi caso con el Excel Object Model 2007, si desean aprender mas de eso –> http://www.packtpub.com/article/microsoft-office-excel-programming-using-vsto) y así interactuar bajo .net (el tema es un poco mas complicado que esto pero no es el objetivo de este post).

Y como Uds. sabrán han habido muchos problemas para sus aplicaciones com+, yo lo tuve especialmente con el tema de compatibilidad (la bendita compatibilidad binaria!!!!), entonces por ahi fui con este tema.

Primero busque en la red y existen algunas soluciones como esta –> http://blogs.msdn.com/charles_sterling/archive/2007/02/21/programmatic-access-to-the-microsoft-office-visual-basic-for-applications-project-system-could-not-be-enabled.aspx , y no me funciono, luego instale service packs, reinstale visual studio, reinstale office y nada de nada….

Entonces busque algunos limpiadores (luego de instalar y desinstalar mucho en mi maquina) y encontré uno muy bueno que me sirvió para otras cosas :p pero igual les paso el dato: Windows Installer CleanUp Utility –> http://support.microsoft.com/default.aspx?scid=kb;en-us;290301

Bueno después de todo esto y verificar realmente mis ensamblados, me di cuenta que tenia ensamblados de office 2003!!!!, eso quiere decir que realmente había un problema de compatibilidad entre 2003 y 2007 con vsto de vs2008 (PIAs de Office)

Microsoft does not guarantee that the Office PIAs will be backwardly compatible or that the various versions of the Office PIAs can be run side-by-side in the same instance of an Office application. Office XP managed code add-ins must be built against the Office XP PIAs. The Office 2003 managed code add-ins must be built against the Office 2003 PIAs. The Office 2007 managed code add-ins must be built against the Office 2007 PIAs. Therefore, if you build an add-in solution that you intend to use with several versions of Office, Microsoft recommends that you build a version of your add-in for each version of Office that you intend to support.”

mas explicaciones y mejores que la mia :p –>

Conclusión –> Instale office 2003 y le hice upgrade a 2007, con ello se soluciono mi problema y ya estoy apunto de terminar otra parte de la solución :) que seguro mas adelante les estaré comentando…

Hasta la próxima…

SSRS 2008 –> Variables + Custom Code + ReportItems!

Este post es en ayuda para alguien que quiera buscar como trabajar con los datos del reporte sin necesidad de ir otra vez a SQL.

Es decir por ejemplo si quisiera este reporte:

Tipo 1

Característica 1 Característica 2 Característica 3…
valores valores valores
  Total2 Total3

Tipo 2

Característica 1 Característica 2 Característica 3 Característica 4 Característica 5
valores valores valores valores valores
      Total4 Total5

….  (varios tipos dinámicos)

Y desear tener una tabla resumen con todas las sumas de cada tabla ademas de una suma total –> Total3 + Total5 + etc

Tabla Resumen

Total3 valor
Total5 valor
TotalN valor
….
TOTAL valor + valor + …

Si vemos el problema sin mucho conocimiento de SSRS, pues decidiríamos tener un stored procedure que me de cada tipo o que me de todos los tipos y otro que me de la tabla resumen. Yo pienso que eso esta de mas, porque la tabla resumen lo podríamos sacar de los datos ya obtenidos para los tipos…

Tenemos muchas opciones para solucionar esto.. por ejemplo podemos trabajar con las variables de Reporting Services 2008 (una nueva característica), la podemos utilizar dando clic derecho en el grupo.

group clic derecho
Pero aun no encuentro la forma de hacer la tabla resumen solo con variables. (tendríamos que combinarlo con Custom Codes, como lo explico mas a adelante).

group variables

y crear la variable con las expresiones o características que deseamos. Un post que me ayudo mucho en esto si lo deseas utilizar fue http://blogs.msdn.com/robertbruckner/archive/2008/07/20/Using-group-variables-in-reporting-services-2008-for-custom-aggregation.aspx es muy bueno porque te lo muestra paso a paso.

La otra forma posible de hacerlo seria utilizar los reports items, propiedad existente desde la versión 2005, para esto si necesitaría sumar esos totales no es mas que: ReportItems!NombreTotal1.value + ReportItems!NombreTotal2.value + … claro que con las validaciones correspondientes como isNothing o isNumeric, etc. Pero esto tiene un pequeño problema, si los tipos del ejemplo crecen dinámicamente en una lista o en una tabla no podría saber como se llama cada ReportItem. Para ello vamos a la siguiente solución :p …

Finalmente, vamos al tema central :p .. que se llama Custom Code. Para mi esto fue una característica en SSRS 2005 (creo que ya venia desde el 2000) que me saco de serios líos cuando quise sacar una gráfica que no venia con Reporting, entonces utilice algunas librerías gráficas, lo referencie y lo combine con unos custom codes, pero no nos desviemos :p

Para este problema en el Custom Code cree las variables publicas que necesite para almacenar los totales:

Public Valores As New System.Collections.Generic.Dictionary(Of String, Decimal)

luego agregamos el siguiente código para llenar este Dictionary

Public Function InsertarTotal(ByVal Titulo As String, ByVal Mkt As Decimal)
   If (Titulo<>Nothing) then
        If Valores.ContainsKey(Titulo) Then
             Valores(Titulo) = Valores(Titulo) + Mkt
        else
            Valores.add(Titulo,Mkt)
        End If
   End If
   InsertarTotal = 0
End Function

Con esta función almaceno en la lista de datos, indizado con el nombre, así que cada vez que haya un total llamo a la función y se inserta en la lista.

y por cada fila que deseamos agregar el valor colocamos: =  … + code.InsertarTotal(Fields!Titulo.Value,Fields!Mkt.Value)

al final tenemos la lista con los valores y ya los ponemos poner en una tabla:

Usamos la misma consulta que nos dan los resultados, pero con un distintc de los totales

Titulos Valores
=Fields!Titulo.value =code.Valores(Fields!Titulo.value)
   

y con esto solucionamos esto, derrepente parezca sencillo a primera vista pero es un tip que me costo un día averiguarlo :p, espero les sea útil.

ya escribiré hasta el próximo break de la chamba :S

P.D.: Me olvide de comentarles que deben tener mucho cuidado con los totales en diferentes hojas!!! porque el total se pierde si es que no hacen algunos cambios :)

Database as a services (I Parte)

Hace unos meses estaba leyendo los temas importantes del Tech-ed de este año y este fue el que me causo mas extrañeza porque no sabia de que trataba (tenia nociones de lo que intentaron ser los servicios de SQL2005 pero nada mas), así que me puse a investigar acerca del tema, y me encontré con todo un mundo, que incluye el famoso termino Cloud, Windows Azure, Microsoft Sync framework, ado.net data services y etcs…

Por ello quise escribir un poco de esto, e introducir al lector a este mundo de moda, primero, definamos 2 términos importantes para este post!!!

  • Cloud: Ciertamente no esta definido del todo, pero podríamos decir que es la nube que representa el mundo desconocido (que no necesitamos conocer) con la que se comunica nuestra aplicación, háganse la idea de que tengo una aplicación y esta se conecta a “algo” y este algo me devuelve los datos que necesito, no me importa saber en que esta programado, ni que infraestructura tiene, ni nada, es ya la evolución de la idea de servicios, existe Cloud para programación, para infraestructura, plataforma y para todo lo que intervenga en este. Si no te ha quedado claro aun, te aconsejo leer lo siguiente:
  • Plataforma como servicios: No solamente obtenemos de los servicios los datos, también podemos tener dentro de nuestro cloud algo que nos almacene datos, algo que comparta nuestro tiempo de procesamiento (como el grid en oracle), algo que haga que el usuario final no sepa donde pasan las cosas, y esto tiene que ver con el tema que me interesa Base de Datos!!!! imagínate que tengas un proceso tan grande y tan costoso como el tener calculadoras de Bonos, Vares, limites (todos temas de finanzas) y tengas muchos lugares donde procesarlos sin necesidad de ser SQL, Windows, etc… a mi me emociona :p

Ahora, entenderán que me sorprendió muchas cosas del Tech-ed (que lo veo vía on-line), y todo se esta relacionando con eso!!!

En SQL 2005 ya podíamos crear una capa de servicios Web (SQL como servidor Http) (http://www.microsoft.com/spain/sql/productinfo/features/top30features.mspx), pero creo yo en SQL 2008 las cosas se ponen mas maduras, como Data Hub, SQL Data Services y la interacción con Windows Azure y herramientas que complementan esto como ado.net Data Services, Microsoft Sync Framework que nos hacen pensar ya en aplicaciones totalmente distribuidas y servicios por todos lados, en línea y no en línea.

Bueno ahora ya centrándonos al tema central, la pregunta seria, como lo aplico en el desarrollo????, ojo: yo soy de las personas que piensan que primero debes tener una base teórica para poder programar!!! por eso esa pequeña introducción :)

Y esa parte de desarrollo lo vamos a ver en la segunda parte de este post :)  (y cuando tenga tiempo de hacer las demos jejejeje)

Bienvenidos!!!!!

Hola a todos,

Seguro nadie leerá esto aun :p .. pero espero pueda servir de ayuda en un futuro a la gente que le gusta estas tecnologias. Desde ya hace un tiempo he querido volver a escribir acerca de los “detalles” que tenemos cuando desarrollamos..

He visto desde aplicaciones mobiles (hace muchos años) hasta aplicaciones de Business Intelligence (en donde tengo mucha experiencia) y ya conociendo poco a poco SQL 2008 y todas sus variantes .net 2008 (asp.net, VSTO, silverlight, etc…) , ademas de Sharepoint, Performance Pont (monitoring, analytics, planning) y muchas cosas mas que vienen con esto.

Espero poder compartir todos mis conocimientos de aca en adelante… (y espero tener el tiempo tambien de escribir todo lo que tengo en mi cabeza :p)

Bueno ahora si empezamos!!!!

P.D: Saludos y gracias al equipo de Geeks por permitirme postear :)