2016/02/17

LEN vs DATALENGTH

PROBLEMA
Seguramente nos hemos topado con estas dos funciones, a primera vista son iguales, pero realmente conocemos para que sirven?

SOLUCION
Con los siguientes ejemplos, espero que podamos comprender mejor su funcionamiento y en que casos podemos ocupar dichas funciones.

LEN
Extrae el numero de caracteres dentro de una variable tipo cadena, sin contar los espacios al final de esta misma. 

DATALENGTH
Extrae el espacio ocupado en memoria por los caracteres contenidos en una variable tipo cadena, sin contar los espacios al final de la misma.

Estas son las diferencias entre ambas funciones, mejor explicado con algunos ejemplos a continuación utilizando tipos de datos, veamos el contenido de las variables que utilizaremos : 

‘’ Cadena vacía para verificar el contenido en los diferentes tipos de datos.
‘1234’ Solo 4 caracteres, numerados en su posición del 1 al 4.
‘1234    ’ 8 caracteres, 4 numerados y 4 con espacios en blanco
'  3456  9 ' 10 caracteres, numerados solo algunas posiciones, el resto con espacios en blanco

Para la explicación de los tipos de datos, les dejo un artículo escrito algunos meses atras
-- TIPO DE DATO: CHAR 
DECLARE @varString1 CHAR(10) = '' 
DECLARE @varString2 CHAR(10) = '1234' 
DECLARE @varString3 CHAR(10) = '1234    ' 
DECLARE @varString4 CHAR(10) = '  3456  9 ' 

SELECT 'CHAR' AS tipoDato, 'LEN' AS funcion 
, LEN( @varString1 ) AS resultado1 
, LEN( @varString2 ) AS resultado2 
, LEN( @varString3 ) AS resultado3 
, LEN( @varString4 ) AS resultado4 

SELECT 'CHAR' AS tipoDato, 'DATALENGTH' AS funcion 
, DATALENGTH( @varString1 ) AS resultado1 
, DATALENGTH( @varString2 ) AS resultado2 
, DATALENGTH( @varString3 ) AS resultado3 
, DATALENGTH( @varString4 ) AS resultado4


-- TIPO DE DATO: NCHAR 
DECLARE @varNstring1 NCHAR(10) = '' 
DECLARE @varNstring2 NCHAR(10) = '1234' 
DECLARE @varNstring3 NCHAR(10) = '1234    ' 
DECLARE @varNstring4 NCHAR(10) = '  3456  9 ' 

SELECT 'NCHAR' AS tipoDato, 'LEN' AS funcion 
, LEN( @varNstring1 ) AS resultado1 
, LEN( @varNstring2 ) AS resultado2 
, LEN( @varNstring3 ) AS resultado3 
, LEN( @varNstring4 ) AS resultado4 

SELECT 'NCHAR' AS tipoDato, 'DATALENGTH' AS funcion 
, DATALENGTH( @varNstring1 ) AS resultado1 
, DATALENGTH( @varNstring2 ) AS resultado2 
, DATALENGTH( @varNstring3 ) AS resultado3 
, DATALENGTH( @varNstring4 ) AS resultado4 


-- TIPO DE DATO: VARCHAR 
DECLARE @varString1 VARCHAR(10) = '' 
DECLARE @varString2 VARCHAR(10) = '1234' 
DECLARE @varString3 VARCHAR(10) = '1234    ' 
DECLARE @varString4 VARCHAR(10) = '  3456  9 ' 

SELECT 'VARCHAR' AS tipoDato, 'LEN' AS funcion 
, LEN( @varString1 ) AS resultado1 
, LEN( @varString2 ) AS resultado2 
, LEN( @varString3 ) AS resultado3 
, LEN( @varString4 ) AS resultado4 

SELECT 'VARCHAR' AS tipoDato, 'DATALENGTH' AS funcion 
, DATALENGTH( @varString1 ) AS resultado1 
, DATALENGTH( @varString2 ) AS resultado2 
, DATALENGTH( @varString3 ) AS resultado3 
, DATALENGTH( @varString4 ) AS resultado4


-- TIPO DE DATO: NVARCHAR 
DECLARE @varNstring1 NVARCHAR(10) = '' 
DECLARE @varNstring2 NVARCHAR(10) = '1234' 
DECLARE @varNstring3 NVARCHAR(10) = '1234    ' 
DECLARE @varNstring4 NVARCHAR(10) = '  3456  9 ' 
 
SELECT 'NVARCHAR' AS tipoDato, 'LEN' AS funcion 
, LEN( @varNstring1 ) AS resultado1 
, LEN( @varNstring2 ) AS resultado2 
, LEN( @varNstring3 ) AS resultado3 
, LEN( @varNstring4 ) AS resultado4 
 
SELECT 'NVARCHAR' AS tipoDato, 'DATALENGTH' AS funcion 
, DATALENGTH( @varNstring1 ) AS resultado1 
, DATALENGTH( @varNstring2 ) AS resultado2 
, DATALENGTH( @varNstring3 ) AS resultado3 
, DATALENGTH( @varNstring4 ) AS resultado4 

Espero que con estos ejemplos, se haya aclarado el panorama con respecto a estas dos funciones.

SALUDOS

2016/02/15

CONCATENANDO, LIDIANDO CON NULLs

PROBLEMA
En nuestra BDs tenemos almacenados valores NULL, en ocasiones tendremos la necesidad de concatenarlas pero que sucede si concatenamos dichos valores, el resultado será NULL ! ! Como puedo manejar esto?

SOLUCION

Existen algunas opciones de solución que podemos utilizar para salir de esta situación, veamos algunas:

COALESCE

De una lista de parametros ingresados, devuelve el primer resultado que no sea NULL.
-- USANDO COALESCE 

SELECT  
COALESCE( 'String1' , NULL, NULL, NULL ) AS resultado1 
, COALESCE( 'String1' , 'String2' , NULL, NULL ) AS resultado2 
, COALESCE( 'String1' , 'String2' , 'String3' , NULL ) AS resultado3 
, COALESCE( 'String1' , 'String2' , 'String3' , 'String4') AS resultado4; 

SELECT  
COALESCE( 'String1' , NULL, NULL, NULL ) AS resultado1 
, COALESCE( NULL , 'String2' , NULL, NULL ) AS resultado2 
, COALESCE( NULL , NULL , 'String3' , NULL ) AS resultado3 
, COALESCE( NULL , NULL , NULL , 'String4') AS resultado4; 

SELECT  
COALESCE( 'String1' , NULL, NULL, NULL ) AS resultado1 
, COALESCE( 'String1' , 'String2' , NULL, NULL ) AS resultado2 
, COALESCE( 'String1' , NULL , 'String3' , NULL ) AS resultado3 
, COALESCE( NULL , NULL , 'String3' , 'String4') AS resultado4

Ahora para concatenar usando COALESCE veamos el siguiente ejemplo:
-- COALESCE COMPLEJO 

DECLARE @varPrimerValorA VARCHAR(50) = ',String1' + NULL +',String3' 
DECLARE @varPrimerValorB VARCHAR(50) = ',String1' + ',String2' +',String3' 
DECLARE @varSegundoValor VARCHAR(50) = ',ContenidoSegundoValor' 

SELECT  
@varPrimerValorA AS varPrimerValorA 
, @varPrimerValorB AS varPrimerValorB 
, @varSegundoValor AS varSegundoValor 

SELECT 
'Inicio' + COALESCE( @varPrimerValorA , @varSegundoValor ) + ',Fin' AS resultado1 
,  'Inicio' + COALESCE( @varPrimerValorB , @varSegundoValor ) + ',Fin' AS resultado2 

CONCAT

Otra opción que podemos utilizar es la función CONCAT; su principal diferencia es que reemplaza NULL por un espacio vacio.
-- USANDO CONCAT  

SELECT   
CONCAT( 'String1' , NULL, NULL, NULL ) AS resultado1  
, CONCAT( 'String1' , 'String2' , NULL, NULL ) AS resultado2  
, CONCAT( 'String1' , 'String2' , 'String3' , NULL ) AS resultado3  
, CONCAT( 'String1' , 'String2' , 'String3' , 'String4') AS resultado4 ;  
 
SELECT   
CONCAT( 'String1' , NULL, NULL, NULL ) AS resultado1  
, CONCAT( NULL , 'String2' , NULL, NULL ) AS resultado2  
, CONCAT( NULL , NULL , 'String3' , NULL ) AS resultado3  
, CONCAT( NULL , NULL , NULL , 'String4') AS resultado4  ; 
 
SELECT   
CONCAT( 'String1' , NULL, NULL, NULL ) AS resultado1  
, CONCAT( 'String1' , 'String2' , NULL, NULL ) AS resultado2  
, CONCAT( 'String1' , NULL , 'String3' , NULL ) AS resultado3  
, CONCAT( NULL , NULL , 'String3' , 'String4') AS resultado4 ;  


-- CONCAT COMPLEJO  

DECLARE @varPrimerValorA VARCHAR(50) = ',String1' + NULL +',String3'  
DECLARE @varPrimerValorB VARCHAR(50) = ',String1' + ',String2' +',String3'  
DECLARE @varSegundoValor VARCHAR(50) = ',ContenidoSegundoValor' 
 
SELECT   
@varPrimerValorA AS varPrimerValorA  
, @varPrimerValorB AS varPrimerValorB  
, @varSegundoValor AS varSegundoValor  ; 
 
SELECT  
'Inicio' + CONCAT( @varPrimerValorA , @varSegundoValor ) + ',Fin' AS resultado1  
,  'Inicio' + CONCAT( @varPrimerValorB , @varSegundoValor ) + ',Fin' AS resultado2 ; 

ISNULL
Dicha función solo acepta dos parametros, el primero es el valor que queremos evaluar para saber si es NULL y el segundo es el valor que reemplazara en caso de que el primero evalue a TRUE.
-- USANDO ISNULL   

DECLARE @varContenidoPrimerValor VARCHAR(50) = 'ContenidoPrimerValor' 
DECLARE @varContenidoSegundoValor VARCHAR(50) = 'ContenidoSegundoValor' 
DECLARE @varNULL VARCHAR(50) = NULL 

SELECT    
ISNULL( @varContenidoPrimerValor , @varContenidoSegundoValor ) AS resultado1   
, ISNULL( @varNULL , @varContenidoSegundoValor ) AS resultado2   
, ISNULL( @varContenidoPrimerValor , @varNULL ) AS resultado3 
, ISNULL( @varNULL , @varNULL ) AS resultado4


-- ISNULL COMPLEJO   

DECLARE @varPrimerValorA VARCHAR(50) = ',String1' + NULL +',String3'   
DECLARE @varPrimerValorB VARCHAR(50) = ',String1' + ',String2' +',String3'   
DECLARE @varSegundoValor VARCHAR(50) = ',ContenidoSegundoValor'   

SELECT    
@varPrimerValorA AS varPrimerValorA   
, @varPrimerValorB AS varPrimerValorB   
, @varSegundoValor AS varSegundoValor ; 

SELECT   
'Inicio' + ISNULL( @varPrimerValorA , @varSegundoValor ) + ',Fin' AS resultado1   
,  'Inicio' + ISNULL( @varPrimerValorB , @varSegundoValor ) + ',Fin' AS resultado2 ; 
CONCAT_NULL_YIELDS_NULL

Permite reemplazar NULL por espacio vacío sin necesidad de alguna función, solo que no es recomedable hacerlo ya que por DEFAULT, SQL SERVER activa está opción precisamente para conocer los resultados donde genere NULL.
-- USANDO CONCAT_NULL_YIELDS_NULL  

-- REEMPLAZANDO NULL POR VACIO 

SET CONCAT_NULL_YIELDS_NULL OFF 
DECLARE @varContenidoPrimerValor VARCHAR(50) = 'ContenidoPrimerValor'  
DECLARE @varContenidoSegundoValor VARCHAR(50) = 'ContenidoSegundoValor'  
DECLARE @varNULL VARCHAR(50) = NULL  

SELECT     
@varContenidoPrimerValor + @varContenidoSegundoValor  AS resultado1    
, @varNULL + @varContenidoSegundoValor AS resultado2    
, @varContenidoPrimerValor + @varNULL AS resultado3  
, @varNULL + @varNULL AS resultado4  
, @varNULL + @varNULL + '' AS resultado5  
GO 
 
-- PERMITIENDO NULL 

SET CONCAT_NULL_YIELDS_NULL ON 
DECLARE @varContenidoPrimerValor VARCHAR(50) = 'ContenidoPrimerValor'  
DECLARE @varContenidoSegundoValor VARCHAR(50) = 'ContenidoSegundoValor'  
DECLARE @varNULL VARCHAR(50) = NULL

SELECT     
@varContenidoPrimerValor + @varContenidoSegundoValor  AS resultado1    
, @varNULL + @varContenidoSegundoValor AS resultado2    
, @varContenidoPrimerValor + @varNULL AS resultado3  
, @varNULL + @varNULL AS resultado4  
, @varNULL + @varNULL + '' AS resultado5  

-- USANDO CONCAT_NULL_YIELDS_NULL  
-- CONCAT_NULL_YIELDS_NULL COMPLEJO 

-- REEMPLAZANDO NULL POR VACIO 

SET CONCAT_NULL_YIELDS_NULL OFF 
DECLARE @varPrimerValorA VARCHAR(50) = ',String1' + NULL +',String3'    
DECLARE @varPrimerValorB VARCHAR(50) = ',String1' + ',String2' +',String3'    
DECLARE @varSegundoValor VARCHAR(50) = ',ContenidoSegundoValor'    

SELECT     
@varPrimerValorA AS varPrimerValorA    
, @varPrimerValorB AS varPrimerValorB    
, @varSegundoValor AS varSegundoValor    

SELECT    
'Inicio' +  @varPrimerValorA + @varSegundoValor + ',Fin' AS resultado1    
,  'Inicio' + @varPrimerValorB + @varSegundoValor + ',Fin' AS resultado2 
GO 
 
-- PERMITIENDO NULL 

SET CONCAT_NULL_YIELDS_NULL ON 
DECLARE @varPrimerValorA VARCHAR(50) = ',String1' + NULL +',String3'    
DECLARE @varPrimerValorB VARCHAR(50) = ',String1' + ',String2' +',String3'    
DECLARE @varSegundoValor VARCHAR(50) = ',ContenidoSegundoValor'  
  
SELECT     
@varPrimerValorA AS varPrimerValorA    
, @varPrimerValorB AS varPrimerValorB    
, @varSegundoValor AS varSegundoValor
   
SELECT    
'Inicio' +  @varPrimerValorA + @varSegundoValor + ',Fin' AS resultado1    
,  'Inicio' + @varPrimerValorB + @varSegundoValor + ',Fin' AS resultado2 
GO 

Ahora si gustan probar, desactiven la opción CONCAT_NULL_YIELDS_NULL para las funciones ISNULL, CONCAT, COALESCE y vean el resultado. 

SALUDOS!

2016/02/11

SSIS, PASANDO VARIABLES A OBJETOS SCRIPT TASK

PROBLEMA

En algunas ocasiones que nos encontremos desarrollando algun ETL sera necesario pasar variables al objeto Script Task, como lo puedo hacer?

SOLUCION

A continuación les mostrare la manera para lograr esto:



int variableINT = (int)Dts.Variables["varInt"].Value;
Boolean variableBOOLEAN = (Boolean)Dts.Variables["varBoolean"].Value;
DateTime variableDATETIME = (DateTime)Dts.Variables["varDateTime"].Value;
Decimal variableDECIMAL = (Decimal)Dts.Variables["varDecimal"].Value;
String variableSTRING = (String)Dts.Variables["varString"].Value;

MessageBox.Show("variableINT=>" + variableINT.ToString() + "\n variableBOOLEAN=>" + variableBOOLEAN.ToString() + "\n variableDATETIME=>" + variableDATETIME.ToString() + "\n variableDECIMAL=>" + variableDECIMAL.ToString() + "\n variableSTRING=>" + variableSTRING.ToString());

Dts.Variables["varInt"].Value = 5555;
Dts.Variables["varString"].Value = "Valor variable STRING modificado.";



int variableINT = (int)Dts.Variables["varInt"].Value;
Boolean variableBOOLEAN = (Boolean)Dts.Variables["varBoolean"].Value;
DateTime variableDATETIME = (DateTime)Dts.Variables["varDateTime"].Value;
Decimal variableDECIMAL = (Decimal)Dts.Variables["varDecimal"].Value;
String variableSTRING = (String)Dts.Variables["varString"].Value;

MessageBox.Show("variableINT=>" + variableINT.ToString() + "\n variableBOOLEAN=>" + variableBOOLEAN.ToString() + "\n variableDATETIME=>" + variableDATETIME.ToString() + "\n variableDECIMAL=>" + variableDECIMAL.ToString() + "\n variableSTRING=>" + variableSTRING.ToString());





Es importante especificar correctamente el nombre dentro del Script Task Editor, ya que de otro modo, nos generara un error.
Dudas o comentarios? Pueden dejar su comentario.

SALUDOS!

2016/02/02

SSIS, NOMBRES DE ARCHIVOS ALMACENADOS EN BD

PROBLEMA
Requerimos generar archivos desde SSIS que a su vez los nombres de estos se encuentren definidos ya en una tabla de SQL SERVER, y que podamos modificarlo de acuerdo a nuestro criterio, que puedo hacer?

SOLUCION
Como ya les he explicado en artículos anteriores ( USANDO FOREACH LOOP CONTAINER EN SSIS y SSIS, GENERANDO ARCHIVOS CON NOMBRES DINAMICOS ), vamos a combinar lo practicado en estos dos artículos, requerimos extraer los nombres de los archivos desde SQL SERVER, leer el resultado con un objeto FOR EACH LOOP CONTAINER, después depositar el nombre en una variable de SSIS y por ultimo conectar dicha variable a la propiedad ConnectionString de la conexión, bien, hagamoslo.

Nuestro primer paso será crear una tabla que contendrá los nombres de los archivos, la Base de datos donde creare dicha tabla es la de ejemplo AdventureWorks:
IF OBJECT_ID( 'dbo.nombreArchivos' ) IS NOT NULL
 DROP TABLE dbo.nombreArchivos; 

CREATE TABLE dbo.nombreArchivos( 
 cveNombreArchivos TINYINT IDENTITY(1,1)
 , nombreArchivo VARCHAR(100)
) 

INSERT INTO dbo.nombreArchivos( nombreArchivo ) 
VALUES( 'windows.txt' ) 
, ( 'sqlServer.asd' )
, ( 'managementStudio.qwe' ) 
, ( 'azureDatabase.ops' )
, ( 'integrationServices.pin' )

SELECT * FROM dbo.nombreArchivos

Nuevamente, con la BD de ejemplo AdventureWorks, de donde extraeremos la información será la tabla Production.Location
Primero necesitamos realizar la conexión a nuestra BD para poder hacer las consultas necesarias, en este caso utilizaré un OLE DB Connection Manager


Creamos la variable que almacenará el contenido del resultado de la consulta de los nombres de los archivos

Procedemos a realizar la consulta y capturar el resultado en la variable de tipo Object resultSet:



Una vez almacenada nuestra consulta en una variable, procederemos a recorrer dicho resultado utilizando un bucle.


Creamos un Data Flow Task para realizar el proceso de carga.



Bien esto fue de la parte de la fuente, ahora vamos con la parte del destino. Primero necesitamos preparar la conexión destino.





Como siguiente paso, ahora arrastramos un Flat File Destination el cual configuraremos de la siguiente manera:


Y nuestro paquete quedara asi:


Y eso es todo, espero que les sirva.

SALUDOS

2016/02/01

SSIS, GENERANDO ARCHIVOS CON NOMBRES DINAMICOS

PROBLEMA:
Requerimos generar un archivo desde SSIS donde depositaremos nuestros datos y que el nombre de dicho archivo cambie de acuerdo a la fecha en la cual fue generado, sin embargo el Flat File Connection Manager necesita del archivo para poder realizar la conexión y tener listo las columnas, los tipos de datos, su longitud entre otras cosas, para poder utilizarla como un destino, que puedo hacer?

SOLUCION:
Necesitamos crear una variable la cual asignaremos una expresión para introducirla a la configuración de un Flat File Connection Manager, les explico como realizar esto, primero es necesario notar que para crear un Flat File Connection Manager este requiere el nombre del archivo, pero el nombre del archivo lo desconocemos por lo tanto, que es lo que tenemos que hacer si el nombre del archivo se generará dinámicamente?

Debemos crear un archivo y después,  abrirlo en el Flat File Connection Manager:

Ahora necesitamos crear una variable de tipo STRING que almacenara el nombre dinámico del archivo que se generará.

La expresion es la siguiente:

"C:\\SSIS\\nombreArchivoDinamico\\archivoPruebaConFormatoFechaYYYYMMDDHHMMSS" + (DT_WSTR,4)YEAR(GETDATE()) 
    + RIGHT("0" + (DT_WSTR,2)MONTH(GETDATE()), 2)
    + RIGHT("0" + (DT_WSTR,2)DAY( GETDATE()), 2) 
    + RIGHT("0" + (DT_WSTR,2)DATEPART("hh", GETDATE()), 2) 
    + RIGHT("0" + (DT_WSTR,2)DATEPART("mi", GETDATE()), 2)
    + RIGHT("0" + (DT_WSTR,2)DATEPART("ss", GETDATE()), 2)
+ ".txt"

Establecemos la propiedad DelayValidation a True

Ahora es necesario asignar nuestra variable a la propiedad ConnectionString de nuestra conexión al archivo.

Creamos una fuente de datos ficticia, puede ser un archivo, una consulta, etc,  para el ejemplo utilizaré un archivo:
Lo abrimos desde un Flat File Connection Manager, el cual nombraremos archivoFuente

Ahora es necesario generar un Data Flow Task que nos permita hacer la carga desde el archivo fuente a nuestro archivo destino, veamos como hacerlo:






Con esto ya podemos generar archivo con nombres dinámicos, la clave de todo esto se encuentra en la correcta asignación del nombre en la variable así como designar la propiedad ConnectionString que recibirá su contenido precisamente de esta variable, después les explicaré como generar archivo XLSx con nombres dinámicos.

Espero que les sirva.

SALUDOS!