2014/10/31

EJECUTAR TAREA PROGRAMADA USANDO CODIGO T-SQL

Una de las muchas necesidades que se nos pueden presentar es ejecutar una tarea programada ( JOB ) desde código T-SQL, bien les mostraré como lograrlo utilizando el procedimiento msdb.dbo.sp_start_job, solo necesitan el nombre de la tarea programada tal y cual como aparece en el Job Activity Monitor.
EXEC msdb.dbo.sp_start_job 'nombreTareaProgramada'

Obtendrán como resultado algo así:

Pero esto solo lo podrán ejecutar siempre y cuando hayan accesado como SA ( System Administrator ), pero por cuestiones de seguridad es necesario ingresar con un usuario con menos permisos, por lo tanto se encontrarán con un error como este:

Para solucionarlo es necesario darle los permisos para que pueda ejecutar dicho procedimiento almacenado localizado en la base de datos msdb.

Primero debemos crear un usuario en la base de datos msdb para nuestro login( dicho login es el que tiene acceso a una base de datos diferente y no tiene permisos sobre la base de datos msdb ), para el ejemplo utilizaré un login llamado loginPrueba y agregamos el rol a nuestro nuevo usuario de la siguiente manera:
USE msdb

CREATE USER userPrueba FOR LOGIN loginPrueba 
GO


EXEC sp_addrolemember N'SQLAgentOperatorRole', N'userPrueba'
La forma gráfica de lograr esto es de la siguiente manera:

Una vez que estemos conectados como SA, abrimos la carpeta Security y damos doble click sobre nuestro login.

Ahora, en el apartado User Mapping seleccionamos la base de datos msdb y escribimos el nombre del usuario y seleccionamos el rol SQLAgentOperatorRole. Es necesario revisar que es lo hace cada rol para evitar cuestiones de seguridad en nuestro servidor, les dejo la liga SQL Server Agent Fixed Database Roles.


Esto es todo, ya podremos ejecutar tareas programadas desde T-SQL.

SALUDOS.

2014/10/15

PREVENT SAVING CHANGES

Cuando han instalado recientemente su SQL SERVER MANAGEMENT STUDIO, es posible que se encuentre con este detalle al momento de hacer cambios a una tabla.

Solo basta con desactivar una opción en el menú Tools-> Options.
Apartado Designers y desactivar Prevent saving changes that require table re-creation.
SALUDOS

2014/10/07

OPERACIONES ENTRE FILA ACTUAL Y N FILAS ANTERIORES/POSTERIORES?

Hace algunos días me enfrente con un problema en el cual era necesario realizar operaciones entre el valor de la columna de la fila actual y 2 filas anteriores y posteriores, después de dar tantas vueltas encontré la solución y se las explico.

Primero crearemos nuestra tabla
IF OBJECT_ID( 'datosPrueba') IS NOT NULL
       DROP TABLE datosPrueba
 
CREATE TABLE datosPrueba ( cve INT IDENTITY(1,1) , particion CHAR(1), valor INT )
GO
 
INSERT INTO datosPrueba( particion , valor )
VALUES( 'a', 2 ) , ( 'a', 3 ) , ( 'a',4 ) , ( 'b', 5 ) , ( 'b',10 ) , ( 'b',20 ) , ( 'b', 34 ) , ( 'b',50 )
Ahora utilizaremos algo similar para hacer sumatorias acumuladas, solo que en esta ocasión agregaremos ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING para filas posteriores y ROWS BETWEEN 2 PRECEDING AND CURRENT ROW para filas anteriores, veamos el ejemplo.
SELECT *
, SUM( valor ) OVER( ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS sm1
, SUM( valor ) OVER( ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS sm2
 FROM datosPrueba
Con ROJO estoy indicando el valor de la fila actual y con AZUL los valores de las filas posteriores para la columna sm1 y para la columna sm2 serían los valores de las filas anteriores. Es necesario señalar que si no hay filas anteriores o posteriores, se tomará NULL.

Veamos otro ejemplo donde también se puede utilizar PARTITION BY para definir nuestros bloques dentro de la consulta.
SELECT *
, SUM( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS sm1
, SUM( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS sm2
 FROM datosPrueba

Además es posible utilizar otra clase de funciones de agregado como COUNT, MIN, MAX, AVG, etc.
IF OBJECT_ID( 'datosPrueba') IS NOT NULL
       DROP TABLE datosPrueba
 
CREATE TABLE datosPrueba ( cve INT IDENTITY(1,1) , particion CHAR(1), valor DECIMAL(5,2) )
GO
 
INSERT INTO datosPrueba( particion , valor )
VALUES( 'a', 2 ) , ( 'a', 3 ) , ( 'a',4 ) , ( 'b', 5 ) , ( 'b',10 ) , ( 'b',20 ) , ( 'b', 34 ) , ( 'b',50 )
 

 SELECT *
, SUM( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS sm1
, SUM( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS sm2
, AVG( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS avg1
, AVG( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS avg2
, MAX( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS mx1
, MAX( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS mx2
, MIN( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS mn1
, MIN( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS mn2
, COUNT( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING ) AS cn1
, COUNT( valor ) OVER( PARTITION BY particion ORDER BY cve ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS cnt2
 FROM datosPrueba

Espero que les sirva.

SALUDOS!