Esdeveniments programats (Scheduled Events / Jobs)
Què són els esdeveniments programats?
Un esdeveniment programat (o job, en terminologia de molts SGBD) és una tasca SQL que s'executa automàticament en moments predefinits, sense intervenció humana. És l'equivalent dels cron jobs del sistema operatiu, però integrat dins del propi SGBD, amb accés directe a les dades i a tota la infraestructura transaccional.
Mentre que els triggers reaccionen a operacions de dades i els procediments es criden explícitament, els esdeveniments programats funcionen orientats al temps: cada hora, cada dia a les 3:00, cada primer diumenge del mes.
gantt
title Exemple de planificació de jobs en un SGBD
dateFormat HH:mm
axisFormat %H:%M
section Diàriament
Neteja de sessions expirades :00:30, 5m
Actualitzacio estadistiques :02:00, 15m
Arxivat de registres antics :03:00, 30m
Generació d'informes :05:00, 20m
section Cada hora
Refresc de vistes materialitzades :00:00, 5m
Verificacio integritat :00:30, 3m
Casos d'ús habituals
| Cas d'ús | Freqüència típica | Descripció |
|---|---|---|
| Neteja de registres antics | Diàriament | Eliminar o arxivar files que superen un cert temps de vida. |
| Arxivat de dades històriques | Setmanalment | Moure dades antigues a taules d'arxiu o bases de dades d'historial. |
| Actualització d'estadístiques | Diàriament | Refrescar les estadístiques del planificador per mantenir plans d'execució òptims. |
| Refresc de vistes materialitzades | Horari / Diari | Actualitzar vistes que agreguen grans volums de dades. |
| Generació d'informes | Diàriament | Calcular i desar indicadors KPI, recomptes, totals. |
| Backup lògic parcial | Diàriament | Exportar taules crítiques com a mesura addicional als backups del sistema. |
| Comprovació d'integritat | Setmanalment | Verificar restriccions, detectar orfes, validar coherència. |
| Enviament d'alertes | Horari | Detectar situacions anòmales i registrar-les o notificar-les. |
| Rotació de logs | Setmanalment | Comprimir o eliminar logs de la pròpia base de dades. |
Mecanismes per a cada motor
Visió general
| Motor | Mecanisme | Integrat? | Configuració necessària |
|---|---|---|---|
| PostgreSQL | pg_cron (extensió) |
No (extensió externa) | Instal·lar l'extensió + postgresql.conf |
| MySQL / MariaDB | EVENT SCHEDULER |
Sí | Activar globalment |
| SQL Server | SQL Server Agent |
Sí (servei extern) | Servei ha d'estar en execució |
| Oracle | DBMS_SCHEDULER |
Sí | Actiu per defecte |
PostgreSQL: pg_cron
pg_cron és una extensió de PostgreSQL que permet programar tasques usant la sintaxi de cron estàndard, directament des de SQL. Les tasques es registren en una taula de la BD postgres i s'executen en el procés de background de PostgreSQL.
Instal·lació i configuració
# En sistemes Debian/Ubuntu:
sudo apt-get install postgresql-16-cron
# En CentOS/RHEL:
sudo yum install pg_cron_16
# A postgresql.conf, afegir:
shared_preload_libraries = 'pg_cron'
cron.database_name = 'postgres' # BD on s'emmagatzemen els jobs
-- Reiniciar PostgreSQL i crear l'extensió:
CREATE EXTENSION pg_cron;
-- Opcional: permetre que altres usuaris programin tasques
GRANT USAGE ON SCHEMA cron TO nom_usuari;
Sintaxi cron
┌──────── minut (0-59)
│ ┌────── hora (0-23)
│ │ ┌──── dia del mes (1-31)
│ │ │ ┌── mes (1-12)
│ │ │ │ ┌ dia de la setmana (0=diumenge, 6=dissabte)
│ │ │ │ │
* * * * *
Exemples:
- 0 3 * * * → cada dia a les 3:00
- */5 * * * * → cada 5 minuts
- 0 2 * * 0 → cada diumenge a les 2:00
- 0 */6 * * * → cada 6 hores (0:00, 6:00, 12:00, 18:00)
- 30 23 1 * * → el primer de cada mes a les 23:30
Gestió de jobs
-- Crear un job
SELECT cron.schedule(
'neteja-sessions-diaria', -- nom del job
'0 3 * * *', -- expressió cron
$$DELETE FROM sessions WHERE expires_at < NOW()$$
);
-- Crear un job que executa un procediment
SELECT cron.schedule(
'arxivat-setmanal',
'0 2 * * 0', -- diumenges a les 2:00
$$CALL arxivar_comandes_antigues(NULL)$$
);
-- Llistar jobs existents
SELECT jobid, jobname, schedule, command, active
FROM cron.job
ORDER BY jobname;
-- Veure l'historial d'execucions
SELECT jobid, start_time, end_time, status, return_message
FROM cron.job_run_details
ORDER BY start_time DESC
LIMIT 20;
-- Modificar l'horari d'un job (per nom)
SELECT cron.alter_job(
job_id := (SELECT jobid FROM cron.job WHERE jobname = 'neteja-sessions-diaria'),
schedule := '0 4 * * *' -- canviar de les 3:00 a les 4:00
);
-- Deshabilitar un job sense eliminar-lo
SELECT cron.alter_job(
job_id := (SELECT jobid FROM cron.job WHERE jobname = 'neteja-sessions-diaria'),
active := false
);
-- Eliminar un job
SELECT cron.unschedule('neteja-sessions-diaria');
-- o per ID:
SELECT cron.unschedule(jobid)
FROM cron.job
WHERE jobname = 'arxivat-setmanal';
MySQL / MariaDB: EVENT SCHEDULER
MySQL té un planificador d'esdeveniments integrat, l'EVENT SCHEDULER, que s'activa com a procés de background del servidor. Els events es defineixen amb la instrucció CREATE EVENT.
Habilitar l'Event Scheduler
-- Verificar l'estat actual
SHOW VARIABLES LIKE 'event_scheduler';
-- Habilitar per a la sessió actual (no persistent)
SET GLOBAL event_scheduler = ON;
-- Per fer-ho persistent, afegir a my.cnf / my.ini:
-- [mysqld]
-- event_scheduler = ON
-- Verificar que està actiu
SHOW PROCESSLIST; -- Ha d'aparèixer "Daemon" amb "Waiting for next activation"
Creació i gestió d'events
-- Event que s'executa una sola vegada (AT)
CREATE EVENT neteja_puntual
ON SCHEDULE AT NOW() + INTERVAL 10 MINUTE
DO
DELETE FROM log_errors WHERE data < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- Event recurrent cada dia a les 3:00
CREATE EVENT neteja_diaria
ON SCHEDULE EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 3 HOUR)
DO
DELETE FROM sessions WHERE expires_at < NOW();
-- Event recurrent amb cos de bloc BEGIN...END
DELIMITER //
CREATE EVENT arxivat_mensual
ON SCHEDULE EVERY 1 MONTH
STARTS '2026-04-01 02:00:00'
COMMENT 'Arxiva comandes completades fa més d''un any'
DO
BEGIN
INSERT INTO comandes_arxiu
SELECT * FROM comandes
WHERE estat = 'completada'
AND data_comanda < DATE_SUB(NOW(), INTERVAL 1 YEAR);
DELETE FROM comandes
WHERE estat = 'completada'
AND data_comanda < DATE_SUB(NOW(), INTERVAL 1 YEAR);
END //
DELIMITER ;
-- Modificar un event
ALTER EVENT neteja_diaria
ON SCHEDULE EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 4 HOUR); -- canviar hora
-- Deshabilitar un event
ALTER EVENT neteja_diaria DISABLE;
-- Tornar a habilitar
ALTER EVENT neteja_diaria ENABLE;
-- Eliminar un event
DROP EVENT IF EXISTS neteja_diaria;
-- Llistar events
SHOW EVENTS FROM nom_base_de_dades;
-- Informació detallada
SELECT event_name, event_type, execute_at, interval_value,
interval_field, status, last_executed
FROM information_schema.EVENTS
WHERE event_schema = DATABASE();
SQL Server: SQL Server Agent
SQL Server Agent és un servei de Windows independent que s'executa junt al motor SQL Server. Gestiona Jobs (tasques), cadascun format per un o més Steps (passos) i associat a un o més Schedules (horaris). Es pot configurar via GUI (SQL Server Management Studio) o via procediments de sistema T-SQL.
Verificació i activació del servei
# Des de PowerShell / línia d'ordres de Windows
sc query SQLSERVERAGENT
net start SQLSERVERAGENT
# O des de SQL Server Configuration Manager (GUI)
Creació de jobs via T-SQL
-- Pas 1: Crear el job
USE msdb;
GO
EXEC sp_add_job
@job_name = N'Neteja diari de sessions',
@description = N'Elimina sessions expirades cada dia a les 3:00',
@enabled = 1,
@notify_level_eventlog = 2; -- Registrar errors a l'Event Log de Windows
-- Pas 2: Afegir un step (pas) al job
EXEC sp_add_jobstep
@job_name = N'Neteja diari de sessions',
@step_name = N'Eliminar sessions expirades',
@subsystem = N'TSQL',
@command = N'DELETE FROM sessions WHERE expires_at < GETDATE();',
@database_name = N'la_meva_bd',
@on_success_action = 1, -- 1 = Continuar al next step
@on_fail_action = 2; -- 2 = Finalitzar amb error
-- Pas 3: Crear un horari
EXEC sp_add_schedule
@schedule_name = N'Cada dia a les 3:00',
@freq_type = 4, -- 4 = Diari
@freq_interval = 1, -- Cada 1 dia
@active_start_time = 030000; -- 03:00:00
-- Pas 4: Associar l'horari al job
EXEC sp_attach_schedule
@job_name = N'Neteja diari de sessions',
@schedule_name = N'Cada dia a les 3:00';
-- Pas 5: Registrar el job al servidor
EXEC sp_add_jobserver
@job_name = N'Neteja diari de sessions';
GO
-- Executar el job manualment per fer una prova
EXEC sp_start_job @job_name = N'Neteja diari de sessions';
-- Veure l'historial d'execucions
SELECT
j.name AS job_nom,
h.run_date,
h.run_time,
h.run_duration,
CASE h.run_status
WHEN 0 THEN 'Fallat'
WHEN 1 THEN 'Correcte'
WHEN 2 THEN 'Reintentant'
WHEN 3 THEN 'Cancel·lat'
END AS estat,
h.message
FROM msdb.dbo.sysjobhistory h
JOIN msdb.dbo.sysjobs j ON j.job_id = h.job_id
WHERE j.name = N'Neteja diari de sessions'
ORDER BY h.run_date DESC, h.run_time DESC;
-- Eliminar un job
EXEC sp_delete_job @job_name = N'Neteja diari de sessions';
GUI de SQL Server Agent
Tot i que és possible gestionar els jobs via T-SQL, l'eina habitual és SQL Server Management Studio (SSMS): dins l'arbre de connexió, a "SQL Server Agent" → "Jobs". Des d'allà podeu crear, editar, executar manualment i veure l'historial de qualsevol job de manera visual.
Oracle: DBMS_SCHEDULER
DBMS_SCHEDULER és el paquet PL/SQL d'Oracle per gestionar tasques programades. És molt complet: suporta expressions de calendari pròpies (més expressives que cron), prioritats, finestres de manteniment, cadenes de jobs (un job dispara el següent), i monitoratge integrat.
Creació de jobs
-- Job senzill: executa un bloc PL/SQL cada dia a les 3:00
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'NETEJA_SESSIONS_DIARIA',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN
DELETE FROM sessions
WHERE expires_at < SYSDATE;
COMMIT;
END;',
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=3; BYMINUTE=0; BYSECOND=0',
enabled => TRUE,
comments => 'Elimina sessions expirades cada dia a les 3:00'
);
END;
/
-- Job que crida un procediment emmagatzemat
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'ARXIVAT_MENSUAL',
job_type => 'STORED_PROCEDURE',
job_action => 'ARXIVAR_COMANDES_ANTIGUES', -- nom del procediment
start_date => TO_TIMESTAMP_TZ('2026-04-01 02:00:00 Europe/Madrid',
'YYYY-MM-DD HH24:MI:SS TZR'),
repeat_interval => 'FREQ=MONTHLY; BYMONTHDAY=1; BYHOUR=2; BYMINUTE=0',
enabled => TRUE,
comments => 'Arxivat mensual de comandes antigues'
);
END;
/
-- Gestió de jobs
-- Habilitar / Deshabilitar
BEGIN
DBMS_SCHEDULER.DISABLE('NETEJA_SESSIONS_DIARIA');
DBMS_SCHEDULER.ENABLE('NETEJA_SESSIONS_DIARIA');
END;
/
-- Executar manualment
BEGIN
DBMS_SCHEDULER.RUN_JOB('NETEJA_SESSIONS_DIARIA');
END;
/
-- Eliminar un job
BEGIN
DBMS_SCHEDULER.DROP_JOB('NETEJA_SESSIONS_DIARIA');
END;
/
-- Llistar jobs
SELECT job_name, enabled, state, run_count, failure_count,
last_start_date, next_run_date
FROM user_scheduler_jobs
ORDER BY job_name;
-- Veure l'historial
SELECT job_name, status, actual_start_date, run_duration, error#
FROM user_scheduler_job_run_details
ORDER BY actual_start_date DESC;
Expressions de calendari d'Oracle
Oracle usa el seu propi llenguatge de calendari (repeat_interval), més expressiu que cron:
FREQ=DAILY; BYHOUR=3; BYMINUTE=0 → Cada dia a les 3:00
FREQ=WEEKLY; BYDAY=SUN; BYHOUR=2 → Cada diumenge a les 2:00
FREQ=MONTHLY; BYMONTHDAY=1; BYHOUR=0 → El primer de cada mes a mitjanit
FREQ=HOURLY; BYMINUTE=30 → Cada hora i mitja
FREQ=MINUTELY; INTERVAL=15 → Cada 15 minuts
FREQ=YEARLY; BYMONTH=JAN; BYMONTHDAY=1 → L'1 de gener de cada any
Exemple pràctic 1: neteja diària de registres antics
-- Taula d'exemple: log_activitat amb molts registres antics
-- Conservem 1 any d'historial i eliminem la resta
SELECT cron.schedule(
'neteja-log-activitat',
'0 3 * * *', -- Cada dia a les 3:00
$$
DELETE FROM log_activitat
WHERE data_hora < NOW() - INTERVAL '1 year';
$$
);
-- Versió amb procediment (recomanada per poder gestionar errors):
CREATE OR REPLACE PROCEDURE neteja_log_activitat()
LANGUAGE plpgsql
AS $$
DECLARE
v_eliminats INT;
BEGIN
DELETE FROM log_activitat
WHERE data_hora < NOW() - INTERVAL '1 year';
GET DIAGNOSTICS v_eliminats = ROW_COUNT;
INSERT INTO log_jobs(job_nom, data_execucio, files_afectades, estat)
VALUES ('neteja_log_activitat', NOW(), v_eliminats, 'OK');
RAISE NOTICE 'Neteja completada: % registres eliminats', v_eliminats;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO log_jobs(job_nom, data_execucio, files_afectades, estat, error)
VALUES ('neteja_log_activitat', NOW(), 0, 'ERROR', SQLERRM);
RAISE;
END;
$$;
SELECT cron.schedule(
'neteja-log-activitat-proc',
'0 3 * * *',
'CALL neteja_log_activitat()'
);
DELIMITER //
CREATE PROCEDURE neteja_log_activitat()
BEGIN
DECLARE v_eliminats INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
INSERT INTO log_jobs(job_nom, data_execucio, estat, error_msg)
VALUES ('neteja_log_activitat', NOW(), 'ERROR', 'Excepció SQL');
RESIGNAL;
END;
DELETE FROM log_activitat
WHERE data_hora < DATE_SUB(NOW(), INTERVAL 1 YEAR);
SET v_eliminats = ROW_COUNT();
INSERT INTO log_jobs(job_nom, data_execucio, files_afectades, estat)
VALUES ('neteja_log_activitat', NOW(), v_eliminats, 'OK');
END //
DELIMITER ;
-- Crear l'event
CREATE EVENT evt_neteja_log
ON SCHEDULE EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 3 HOUR)
COMMENT 'Neteja logs amb més d''un any d''antiguitat'
DO CALL neteja_log_activitat();
-- Procediment de neteja
CREATE OR ALTER PROCEDURE neteja_log_activitat
AS
BEGIN
SET NOCOUNT ON;
DECLARE @eliminats INT;
BEGIN TRY
DELETE FROM log_activitat
WHERE data_hora < DATEADD(YEAR, -1, GETDATE());
SET @eliminats = @@ROWCOUNT;
INSERT INTO log_jobs(job_nom, data_execucio, files_afectades, estat)
VALUES ('neteja_log_activitat', GETDATE(), @eliminats, 'OK');
END TRY
BEGIN CATCH
INSERT INTO log_jobs(job_nom, data_execucio, estat, error_msg)
VALUES ('neteja_log_activitat', GETDATE(), 'ERROR', ERROR_MESSAGE());
THROW;
END CATCH;
END;
GO
-- Job a SQL Server Agent:
USE msdb;
EXEC sp_add_job @job_name = N'Neteja log activitat diari';
EXEC sp_add_jobstep @job_name = N'Neteja log activitat diari',
@step_name = N'Executar neteja',
@command = N'EXEC neteja_log_activitat',
@database_name = N'la_meva_bd';
EXEC sp_add_schedule @schedule_name = N'Diari 3h',
@freq_type = 4, @freq_interval = 1,
@active_start_time = 030000;
EXEC sp_attach_schedule @job_name = N'Neteja log activitat diari',
@schedule_name = N'Diari 3h';
EXEC sp_add_jobserver @job_name = N'Neteja log activitat diari';
CREATE OR REPLACE PROCEDURE neteja_log_activitat
AS
v_eliminats NUMBER;
BEGIN
DELETE FROM log_activitat
WHERE data_hora < ADD_MONTHS(SYSDATE, -12);
v_eliminats := SQL%ROWCOUNT;
COMMIT;
INSERT INTO log_jobs(job_nom, data_execucio, files_afectades, estat)
VALUES ('neteja_log_activitat', SYSDATE, v_eliminats, 'OK');
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
INSERT INTO log_jobs(job_nom, data_execucio, estat, error_msg)
VALUES ('neteja_log_activitat', SYSDATE, 'ERROR', SQLERRM);
COMMIT;
RAISE;
END neteja_log_activitat;
/
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_NETEJA_LOG',
job_type => 'STORED_PROCEDURE',
job_action => 'NETEJA_LOG_ACTIVITAT',
repeat_interval => 'FREQ=DAILY; BYHOUR=3; BYMINUTE=0; BYSECOND=0',
enabled => TRUE
);
END;
/
Exemple pràctic 2: refresc setmanal d'estadístiques
-- Actualitzar les estadístiques de totes les taules principals
-- per mantenir plans d'execució òptims
CREATE OR REPLACE PROCEDURE refrescar_estadistiques()
LANGUAGE plpgsql
AS $$
BEGIN
ANALYZE comandes;
ANALYZE linies_comanda;
ANALYZE productes;
ANALYZE clients;
ANALYZE log_activitat;
RAISE NOTICE 'Estadístiques actualitzades a %', NOW();
INSERT INTO log_jobs(job_nom, data_execucio, estat)
VALUES ('refrescar_estadistiques', NOW(), 'OK');
END;
$$;
SELECT cron.schedule(
'refresc-estadistiques-setmanal',
'0 1 * * 0', -- Cada diumenge a la 1:00
'CALL refrescar_estadistiques()'
);
DELIMITER //
CREATE EVENT evt_refresc_estadistiques
ON SCHEDULE EVERY 1 WEEK
STARTS (TIMESTAMP(CURRENT_DATE - WEEKDAY(CURRENT_DATE) + 6) + INTERVAL 1 HOUR)
COMMENT 'Actualitza estadístiques de les taules principals cada diumenge a la 1:00'
DO
BEGIN
ANALYZE TABLE comandes;
ANALYZE TABLE linies_comanda;
ANALYZE TABLE productes;
ANALYZE TABLE clients;
INSERT INTO log_jobs(job_nom, data_execucio, estat)
VALUES ('refresc_estadistiques', NOW(), 'OK');
END //
DELIMITER ;
-- SQL Server: actualitzar estadístiques amb UPDATE STATISTICS
CREATE OR ALTER PROCEDURE refrescar_estadistiques
AS
BEGIN
SET NOCOUNT ON;
UPDATE STATISTICS comandes WITH FULLSCAN;
UPDATE STATISTICS linies_comanda WITH FULLSCAN;
UPDATE STATISTICS productes WITH FULLSCAN;
UPDATE STATISTICS clients WITH FULLSCAN;
INSERT INTO log_jobs(job_nom, data_execucio, estat)
VALUES (N'refresc_estadistiques', GETDATE(), N'OK');
END;
GO
-- Job setmanal (diumenge a la 1:00)
USE msdb;
EXEC sp_add_job @job_name = N'Refresc estadístiques setmanal';
EXEC sp_add_jobstep @job_name = N'Refresc estadístiques setmanal',
@step_name = N'UPDATE STATISTICS',
@command = N'EXEC refrescar_estadistiques',
@database_name = N'la_meva_bd';
EXEC sp_add_schedule
@schedule_name = N'Setmanal diumenge 1h',
@freq_type = 8, -- 8 = Setmanal
@freq_interval = 1, -- Diumenge (bitmask: 1=diumenge)
@freq_recurrence_factor = 1,
@active_start_time = 010000;
EXEC sp_attach_schedule @job_name = N'Refresc estadístiques setmanal',
@schedule_name = N'Setmanal diumenge 1h';
EXEC sp_add_jobserver @job_name = N'Refresc estadístiques setmanal';
-- Oracle: DBMS_STATS.GATHER_SCHEMA_STATS per actualitzar estadístiques
CREATE OR REPLACE PROCEDURE refrescar_estadistiques
AS
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'COMANDES',
cascade => TRUE
);
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'LINIES_COMANDA',
cascade => TRUE
);
DBMS_STATS.GATHER_TABLE_STATS(
ownname => USER,
tabname => 'PRODUCTES',
cascade => TRUE
);
INSERT INTO log_jobs(job_nom, data_execucio, estat)
VALUES ('refresc_estadistiques', SYSDATE, 'OK');
COMMIT;
END refrescar_estadistiques;
/
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_REFRESC_STATS',
job_type => 'STORED_PROCEDURE',
job_action => 'REFRESCAR_ESTADISTIQUES',
repeat_interval => 'FREQ=WEEKLY; BYDAY=SUN; BYHOUR=1; BYMINUTE=0',
enabled => TRUE,
comments => 'Actualitza estadístiques cada diumenge a la 1:00'
);
END;
/
Monitoratge i consulta de jobs
-- Llistar tots els jobs actius
SELECT jobid, jobname, schedule, active, username
FROM cron.job
ORDER BY jobname;
-- Historial de les darreres 50 execucions
SELECT
j.jobname,
r.start_time,
r.end_time,
r.end_time - r.start_time AS durada,
r.status,
r.return_message
FROM cron.job_run_details r
JOIN cron.job j ON j.jobid = r.jobid
ORDER BY r.start_time DESC
LIMIT 50;
-- Jobs fallats
SELECT j.jobname, r.start_time, r.return_message
FROM cron.job_run_details r
JOIN cron.job j ON j.jobid = r.jobid
WHERE r.status = 'failed'
ORDER BY r.start_time DESC;
-- Llistar tots els jobs amb el seu estat
SELECT
j.name AS job_nom,
j.enabled,
j.description,
h.run_date AS darrera_execucio,
CASE h.run_status
WHEN 0 THEN 'Fallat'
WHEN 1 THEN 'Correcte'
WHEN 3 THEN 'Cancel·lat'
END AS darrer_resultat,
s.next_run_date,
s.next_run_time
FROM msdb.dbo.sysjobs j
LEFT JOIN msdb.dbo.sysjobhistory h ON h.job_id = j.job_id
AND h.step_id = 0 -- step 0 = resultat global del job
LEFT JOIN msdb.dbo.sysjobschedules js ON js.job_id = j.job_id
LEFT JOIN msdb.dbo.sysschedules s ON s.schedule_id = js.schedule_id
ORDER BY j.name;
-- Llistar jobs actius
SELECT
job_name,
job_type,
state,
enabled,
run_count,
failure_count,
last_start_date,
next_run_date,
comments
FROM user_scheduler_jobs
ORDER BY job_name;
-- Historial d'execucions
SELECT
job_name,
status,
actual_start_date,
run_duration,
error#,
additional_info
FROM user_scheduler_job_run_details
ORDER BY actual_start_date DESC
FETCH FIRST 50 ROWS ONLY;
Miniactivitat — AC0407
Miniactivitat — AC0407 · Planificació de manteniment automatitzat
Disposeu d'una BD amb les taules: comandes, linies_comanda, productes, clients, sessions_usuari, log_errors, estadistiques_diaries.
Tasca 1 — Neteja diària:
Creeu un job que s'executi cada dia a les 2:30 i faci les tasques següents en aquest ordre:
1. Elimini les sessions d'usuari amb expires_at anterior a ara.
2. Elimini els errors de log amb data anterior a 90 dies.
3. Insereixi un registre a log_jobs indicant quants registres ha eliminat de cada taula i el temps total d'execució.
Tasca 2 — Resum diari:
Creeu un job que s'executi cada dia a les 23:55 i calculi les estadístiques del dia (nombre de comandes, import total, producte més venut, client amb més compres) i les insereixi a estadistiques_diaries.
Tasca 3 — Simulació i verificació:
Executeu els jobs manualment (sense esperar a l'hora programada) i verifiqueu que els registres s'han creat correctament a log_jobs i estadistiques_diaries.
Tasca 4 — Alarma per errors:
Amplieu el job de la Tasca 1 perquè, si es produeix un error en qualsevol dels passos, ho registri a log_jobs amb el missatge d'error i continuï amb el pas següent (no ha d'aturar-se en el primer error).
Entrega: Arxiu SQL amb els procediments i la configuració dels jobs per al motor escollit. Incloeu captures de pantalla (o la sortida de text) que demostrin que els jobs s'han executat correctament i que el registre a log_jobs és correcte.