Mostrando entradas con la etiqueta Programación SQL. Mostrar todas las entradas
Mostrando entradas con la etiqueta Programación SQL. Mostrar todas las entradas

domingo, 22 de febrero de 2015

Programar columna acumulada SQL en dos líneas

Buenas estoy de vuelta por acá en esta ocasión quiero compartirles un forma bastante interesante de como programar el acumulado de una columna para una tabla en SQL. Existen varias formas de programar esto, la más común y que pienso a la mayoría de nosotros se nos ocurriría sería crear un cursor el cual vaya recorriendo la columna y acumulado con una variable auxiliar. Algo como esto:

--Declaración de la tabla temp a utilizar para el ejemplo.
DECLARE @TABLA AS TABLE (
 CODIGO INT NOT NULL IDENTITY(1,1),
 DATO DECIMAL(10,2),
 ACUMULADO DECIMAL(10,2) DEFAULT 0
)
--Agregamos algunos datos a la tabla.
INSERT INTO  @TABLA (DATO) 
 VALUES (5),(10),(8),(9),(15),(20)

--Declaración de variables y cursor a utilizar 
DECLARE @Cod INT,@Dato DECIMAL (10,2),@DatoAcum DECIMAL (10,2)=0
DECLARE C2 CURSOR FOR SELECT CODIGO,DATO FROM @TABLA
OPEN C2
FETCH C2 INTO @Cod,@Dato
--Ciclo para recorrer el cursor.
WHILE @@FETCH_STATUS = 0
BEGIN
 --Acumulamos el dato.
 SET @DatoAcum += @Dato
 --Actualizamos la columna  con los datos acumulados hasta el momento
 UPDATE @TABLA SET ACUMULADO=@DatoAcum WHERE CODIGO=@Cod
 
 FETCH C2 INTO @Cod,@Dato 
END
CLOSE C2
--Obtenemos el resultado
SELECT * FROM @TABLA


Veamos el resultado del código



Como podemos ver es una implementación valida, resuelve nuestro problema y acumula la columna de manera exitosa, pero a pesar de esto quise buscar otra manera más corta de poder resolver la misma situación y fue donde encontré como hacerlo con únicamente un par de líneas. Para esto utilice una variable del mismo tipo de dato de la columna a acumular, y una sentencia update la cual encierra toda la ciencia del código. Sin más explicación veamos el código que es bastante sencillo.

--Declaración de la tabla temp a utilizar para el ejemplo.
DECLARE @TABLA AS TABLE (
 CODIGO INT NOT NULL IDENTITY(1,1),
 DATO DECIMAL(10,2),
 ACUMULADO DECIMAL(10,2) DEFAULT 0
)
--Agregamos algunos datos a la tabla.
INSERT INTO  @TABLA (DATO) 
 VALUES (5),(10),(8),(9),(15),(20)
 
--Declaración de variables a utilizar
DECLARE @ACUM DECIMAL(10,2)=0
--Sentencia UPDATE la cual utiliza la variable de tal forma que permite calcular el acumulado
UPDATE @TABLA SET  @ACUM=ACUMULADO=@ACUM+DATO
  
--Obtenemos el resultado
SELECT * FROM @TABLA

Veamos el resultado del código


Y listo en solo un par líneas y de una manera mucho más eficiente logramos obtener el mismo resultado que cuando utilizamos el cursor. Espero el código compartido les sea de ayuda y logren ahorrarse algunas líneas de código cuando tengan que resolver algo similar. Gracias por su tiempo!!

martes, 23 de diciembre de 2014

Convertir primer letra mayúscula y el resto en minúscula con SQL

En algunas situaciones es necesario convertir una cadena de caracteres de minúsculas a mayúsculas o viceversa, esto en SQL es muy fácil gracias a la funciones UPPER y LOWER. Pero qué pasa si queremos que la cadena tenga un formato de capitalización o en palabras más sencillas, la primera letra en mayúscula y el resto de letras en minúscula?? No existe una función específica en SQL Server que nos permita solucionar este problema, pero si es posible programar una que lo solucione. Por lo que compartiré el código de una solución que me ha funcionado y puede que a ustedes también. Este es el código:

DROP FUNCTION ConvierteMayusculasMinusculas
GO

CREATE FUNCTION ConvierteMayusculasMinusculas(@Cadena VARCHAR(MAX),@Delimitador VARCHAR(100)=' ')
RETURNS VARCHAR(MAX)
AS
BEGIN    

DECLARE @Resultado VARCHAR(MAX)
DECLARE @CadenaAux VARCHAR(8000)
IF CHARINDEX(@Delimitador,@Cadena,0) <> 0
BEGIN
 --Ciclo para recorrer la cadena.
 WHILE CHARINDEX(@Delimitador,@Cadena,0) <> 0
 BEGIN
     SELECT
   -- Obtenemos la primer parte de la cadena hasta el separador
   @CadenaAux=RTRIM(LTRIM(SUBSTRING(@Cadena,1,CHARINDEX(@Delimitador,@Cadena,0)-1))),
   --Obetenemos el resto de la cadena después del delimitador 
   @Cadena=RTRIM(LTRIM(SUBSTRING(@Cadena,CHARINDEX(@Delimitador,@Cadena,0)+LEN(@Delimitador),LEN(@Cadena))))
   --Evaluamos que la cadena tenga más de 2 caracteres para evitar transformar artículos (el,la,un)
   IF (LEN(@CadenaAux)>  2)
    --En caso que la cadena tenga más de 4 caracteres hacemos la conversión (Primer carácter mayúscula y los otros en minúscula)
    SET @Resultado= ISNULL(@Resultado,'') + UPPER(SUBSTRING(@CadenaAux,1,1)) +  LOWER(SUBSTRING (@CadenaAux,2,LEN(@CadenaAux)-1)) + ' '
   ELSE
    SET @Resultado= ISNULL(@Resultado,'') + LOWER( @CadenaAux) + ' '
 END
 END   
-- Validación necesaria en el caso que las cadenas solo tengan una palabra y utilizada al final de la conversión.
IF  CHARINDEX(@Delimitador,@Cadena,0)  = 0
BEGIN
 SET @Resultado= ISNULL(@Resultado,'') + UPPER(SUBSTRING(@Cadena,1,1)) +  LOWER(SUBSTRING (@Cadena,2,LEN(@Cadena)-1)) + ' '
END
RETURN LTRIM(RTRIM(@Resultado))
END  
GO

Como podemos ver en el código anterior se reciben dos parámetros que sería la cadena a convertir y un delimitador el cual sería el carácter que separa cada palabra a convertir (La opción default es un espacio en blanco). Veamos el resultado de una prueba para convertir la cadena "juan arias soto" por "Juan Arias Soto", utilizando como delimitador el carácter default.






El único inconveniente que podemos encontrar en el código es que solo valido palabras con menos de dos caracteres para no convertir a mayúsculas por lo que palabras como "del, las, etc." van a sufrir la conversión, en este caso si se aumenta el largo de caracteres de la validación podría funcionar pero puede que algunas palabras que no deseamos convertir lo hagan y viceversa. Para mi podría hacerse una mejora en la validación con una pequeña estructura que controle las palabras que no deben convertirse según el caso y así habrá seguridad de que cualquier palabra ajena a dicha estructura cambiara. Bueno espero les sea de ayuda a alguno este pequeño código, Gracias y Saludos. 

lunes, 15 de diciembre de 2014

Concatenar registros de columna en cadena (COALESCE)

En un post anterior vimos cómo realizar un split en SQL, con el cual dada una cadena separada por un carácter delimitador es posible dividirla y devolverla a manera de consulta de una tabla.
Ahora me gustaría compartir  un pequeño código que permite hacer lo contrario, ósea en base a una consulta de una tabla, tomar una columna específica y generar un string concatenando cada row de la consulta en la cadena y separándola con un carácter delimitador.

Veamos un ejemplo para entender la dinámica del problema y su respectiva solución. Para esta haremos uso de  una tabla temporal de Usuarios, la cual tiene una columna Nombre que su consulta nos devuelve lo siguiente:



Ahora queremos concatenar todos estos nombres en una cadena, cada uno separado por coma. Algo así:

"Juan,  Carlos, Sofía, Ana, Paco, Viviana, Mía, Keylor"

Para la solución haremos uso de la función COALESCE la cual nos brinda esta funcionalidad. El único inconveniente es que todos los valores de la columna deben ser distintos de NULL para que esta solución funcione de manera correcta.

Veamos el código del ejemplo  Aclaro que se utilizó una tabla temporal solo para modo de ejemplo, pero es posible también utilizar una tabla normal de la Base de Datos.

--Tabla temporal de usuarios
DECLARE @Usuarios AS TABLE(
 Nombre VARCHAR(255)
)

--Agregamos varios datos la tabla.
INSERT INTO @Usuarios (Nombre)VALUES 
 ('Juan'),('Carlos'),('Sofía'),('Ana'),('Paco'),('Viviana'),('Mía'),('Keylor')

--Variable donde se guardara la cadena generada.
DECLARE @STR_ACTIVIDADES AS VARCHAR(MAX)

--Select para crear la cadena basados en la columna nombre de la tabla @Usuarios 
--Concatenamos en la cadena @STR_ACTIVIDADES cada row separado por coma.
SELECT  
 @STR_ACTIVIDADES = COALESCE(@STR_ACTIVIDADES + ', ', '') + Nombre
FROM 
 @Usuarios
 
 --Imprimimos la cadena para ver el resultado.
PRINT @STR_ACTIVIDADES

Ahora veamos el resultado que obtenemos al ejecutar el código anterior.


Listo!!! Problema solucionado....
Esto puede ser muy útil a la hora de presentar reportes donde se requiera  resumir información de varias rows en un mismo campo. Espero que el código les sea de ayuda, sin más por el momento me despido hasta pronto!!

domingo, 23 de febrero de 2014

Split en SQL (Convertir cadena en consulta)

Como podríamos separar en SQL una cadena con un formato especifico, la cual contiene varios datos separados por un delimitador? Bueno es fácil se realiza un split a la cadena.
 El problema es que SQL no tiene una función especifica para realizar esta acción, por lo que una solución seria implementar nuestra propia función Split. Lo que haremos es crear una función la cual reciba como parámetros una cadena y un delimitador tipo varchar,  y esta separara cada uno de los valores de la cadena  y los insertara como filas a una variable tipo tabla, desde la cual ya podemos utilizarlos como si fueran registros separados.

Veamos el código de esta función:

CREATE FUNCTION Split 
(
 @CADENA AS VARCHAR (MAX),
 @DELIMITER AS VARCHAR(10)
)
RETURNS @tt TABLE(item VARCHAR(255))
AS
BEGIN
 SET @CADENA+= @DELIMITER
 DECLARE @AUX AS VARCHAR(255)
 WHILE (LEN(@CADENA) > 0) 
 BEGIN
  SET @AUX= SUBSTRING(@CADENA, 1,CHARINDEX(@DELIMITER, @CADENA)-1)
  INSERT INTO @tt VALUES(@AUX)
  SET @CADENA= SUBSTRING(@CADENA,LEN(@AUX)+2,Len(@CADENA))
 END
 RETURN;
END

Ahora veamos un ejemplo supongamos que tenemos una cadena con nombres de personas separados por coma, entonces ejecutemos la función para ver su resultado.




Como podemos ver obtuvimos la tabla con todos los rows que teníamos en la cadena. Ahora podemos hacerlo con cualquier cadena inclusive con cualquier delimitador. Bueno me despido y espero que les sea de ayuda el código.