domingo, 29 de noviembre de 2015

Listas y Linq

Linq definitivamente es una herramienta que necesitamos dominar, son muchos los escenarios en los que podemos aprovechar su potencia para simplificar las tareas que otrora nos tomaría varias líneas de código. Aquí unas pequeñas pinceladas con arreglos y listas.

Supongamos que tenemos dos arreglos de enteros y necesitamos saber si ambos se intersecan y cuáles son los números que comparten. Con Linq sería algo así:

static void Main(string[] args)
{
    int[] x = { 1, 2, 3, 4, 5 };
    int[] y = { 2, 4, 6 };
    int[] z = x.Intersect(y).ToArray();
    System.Diagnostics.Debug.WriteLine("Resultado: " + 
    string.Join(",", z.Select(s => s.ToString())));
}
¡Simple!
Otro ejemplo
Supongamos que tenemos la siguiente clase
public class Empleado
{
    public int idEmpleado { get; set; }
    public string nomEmpleado { get; set; }
    public decimal mtoSalario { get; set; }
}
Tenemos un array de enteros y queremos inicializar una lista de empleados únicamente con los id a partir del array, procedemos así;
static void Main(string[] args)
{
    int [] ids =  { 1, 2, 3, 4, 5 };
    List<Empleado> empleados = ids
        .Select(i => new Empleado() { idEmpleado = i })
        .ToList();
    System.Diagnostics.Debug.WriteLine("Cantidad: " + empleados.Count);
}
Una más. Supongamos que adicionalmente a la clase anterior de tenemos otra correspondiente a clientes
public class Cliente
{
    public int idCliente { get; set; }
    public string nomCliente { get; set; }
}
Supongamos que comparten un mismo origen, de manera que un cliente y empleado con la misma id, son la misma persona, teniendo dos listas: una de empleados y otra de clientes, queremos saber cuáles empleados también son clientes, entonces:
static void Main(string[] args)
{
    //Clientes
    List<Cliente> clientes = new List<Cliente> (){
        new Cliente() {idCliente=1, nomCliente= "María"}, 
        new Cliente () {idCliente=2, nomCliente="Jose"},
        new Cliente() {idCliente=3, nomCliente="David"}, 
        new Cliente() {idCliente=4,nomCliente="Ana"} 
    };

    //Empleados
    List<Empleado> empleados = new List<Empleado>(){
        new Empleado() {idEmpleado=2, nomEmpleado="Jose", mtoSalario=3500},
        new Empleado() {idEmpleado=4, nomEmpleado="Ana", mtoSalario=5500},
        new Empleado() {idEmpleado=6, nomEmpleado="Carlos", mtoSalario=3500}
    };

    //ids de clientes
    List<int> idsClientes = clientes.Select(s => s.idCliente).ToList();

    //Empleados que son Clientes
    List<Empleado> empleadosClientes = empleados
        .Where(e => idsClientes.Contains(e.idEmpleado))
        .ToList();

    System.Diagnostics.Debug.WriteLine("Empleados y Clientes: " + string.Join(", ", empleadosClientes.Select(c => c.nomEmpleado.ToString())));
}
Como podemos ver son muchas las posibilidades que nos ofrece Linq, o sus Extension Methods para ayudarnos en nuestra labor.

Leia Mais…

sábado, 24 de octubre de 2015

RPAD y LPAD en TSQL

Son un par de funciones que los que algún día estuvimos trabajando con Oracle estrañamos en SQL Server, Básicamente permiten rellenar a la izquierda o derecha con un caracter dado. Aquí una implementación de ambas en T-SQL

--Permite rellenar con un caracter dado a la izquierda hasta completar
-- la longitud deseada
CREATE FUNCTION [dbo].[fnPADL](
 @strOrigen VARCHAR(50), --String original
 @intlen INT,            --longitud a completar
 @chrCaracter CHAR)      --Caracter con el que se rellena
 RETURNS VARCHAR(50)
 AS 
 BEGIN
    DECLARE @len INT = LEN(@strOrigen)
    RETURN (
        CASE 
            WHEN @len < @intlen THEN REPLICATE(@chrCaracter, @intlen - @len) + @strOrigen 
            ELSE  @strOrigen
        END)
END

--Permite rellenar con un caracter dado a la derecha hasta completar
-- la longitud deseada
CREATE FUNCTION [dbo].[fnPADR](
 @strOrigen VARCHAR(50), --String original
 @intlen INT,            --longitud a completar
 @chrCaracter CHAR)      --Caracter con el que se rellena
 RETURNS VARCHAR(50)
 AS 
 BEGIN
    DECLARE @len INT = LEN(@strOrigen)
    RETURN (
        CASE 
            WHEN @len < @intlen THEN  @strOrigen + REPLICATE(@chrCaracter, @intlen - @len)
            ELSE  @strOrigen
        END)
END
Ambas funciones se aseguran que si la longitud de la palabra es mayor o igual a la longitud a cubrir devuelva la misma palabra.

Su forma de utilización sería
SELECT DBO.fnPADL ('HOLA',6,'X')
--devuelve: XXHOLA

SELECT DBO.fnPADR ('HOLA',6,'X')
-- devuelve: HOLAXX

SELECT DBO.fnPADL ('HOLA',2,'X')
-- devuelve: HOLA

Es muy muy importante a tener en cuenta que aunque estén disponibles las UDF (User-Defined Function) que devuelven escalares (como las que acabamos de definir) no es muy recomendable su uso, principalmente con grandes conjuntos de datos, En otro post intentaré ahondar mas en el por qué, quizás con algunas comparativas pero de momento el consejo sería: siempre que sea posible usar la lógica "in line" o dentro de la misma sentencia SQL, por ejemplo es más eficiente esto
SELECT REPLICATE('X',6 - LEN(miColumna)) + miColumna
FROM miTabla
en lugar de esto:
SELECT  DBO.fnPADL (miColumna,6,'X')
FROM miTabla

Obviamente con una cantidad de datos significativa, Además para usar la primera sentencia tenemos que estar seguros que la longitud de miColumna no es mayor a 6.

En todo caso recordar que si vamos a usar UDF escalares debemos realizar pruebas con buenos volúmenes de datos.

Leia Mais…

viernes, 18 de septiembre de 2015

Error en instalación de SQL Server 2014 en Windows 10


Hace ya un tiempo que migré de Windows 8.1 a Windows 10 pro. En el proceso instalé Visual Studio  2013 sin ningún problema pero al tratar de instalar el SQL server 2014 comenzaron los problemas:




Intenté varias soluciones, todas sin ningún efecto. Luego de revisarlo incluso con técnicos de Microsoft y a pesar de que ellos tampoco lograron resolver el problema, si me pusieron en la dirección correcta.

Aquí dejo los pasos con los que logré solventar la situación:

Primero se intentó instalar Visual C++ 2005, sin embargo este a su vez producía un error similar al que producía la instalación de SQL Server solo que en lugar de Microsoft.VC80.CRT era Microsoft.VC80.ATL por lo que determinamos que el problema era más profundo.

Lo siguiente fue levantar un command promp con privilegios de administrador y ejecutar el siguiente comando:

sfc /scannow

Este arrojó lo siguiente:
There is a system repair pending which requires reboot to complete. Restart Windows and run sfc again.”

Fue aquí cuando relacioné con el problema una circunstancia que no había tomado en cuenta anteriormente: cada vez que apagaba o reiniciaba mi laptop el Windows me indicaba que habían actualizaciones pendientes por descargar y/o instalar, yo simplemente dejaba que terminase siempre sin darle mayor relevancia.

Lo que pasaba en realidad es que en alguna de estas instalaciones el sistema operativo no había podido finalizar el proceso adecuadamente y el archivo pending.xml en la carpeta del sistema, que es el cargado de manejar estos aspectos, se había corrompido.

Para arreglar este problema lo que se debe hacer es ir a la consola de recuperación (recovery console) de Windows y ejecutar cierto comando. Hago un paréntesis aquí para explicar cómo llegar a la consola re recuperación: 

Lo más sencillo es, usando la búsqueda de Windows (tecla de Windows + q), digitar “Recovey Settings”. Seleccionando la opción correspondiente nos llevará a una pantalla como la siguiente

Aquí seleccionamos “Restart Now”. El sistema se iniciará e ingresa a la consola de recuperación


 En esta seleccionamos la opción de "Troubleshoot"


Y en esta la opción de “Advanced options


Finalmente seleccionamos “Command Prompt


Ya estando en la ventana de comandos ejecutamos la siguiente línea:


dism.exe /image:C:\ /cleanup-image /revertpendingactions

Cuando nos indique que el proceso se ejecutó satisfactoriamente reiniciamos el equipo. 
Para asegurarnos que todo esté correcto volvemos a ejecutar, en un command prompt con permisos de administrador, el comando:

sfc /scannow

Esta vez nos debe indicar, una vez finalizado, que no hay ningún problema con la integridad del sistema.

Entonces procedemos a instalar el Visual C++ 2005 x64, en mi caso, ya sin ningún problema. Antes de proceder a la instalación de SQL SERVER vamos a la opcion“Turn Windows Features On of Off” y nos aseguramos que la casilla correspondiente a ."Net Framework 3.5 (Includes .Net 2.0 and 3.0)” este marcada (si no lo esta la marcamos y reiniciamos la máquina).


Finalmente podemos instalar SQL Server sin ningún problema


Leia Mais…