Introduction
Many Oracle environments run two scheduling mechanisms side by side: DBMS_SCHEDULER (modern) and DBMS_JOB (legacy). Each has its own commands, dictionaries, and semantics: “enabled"” on one side, “broken” on the other; DBA_SCHEDULER_* here, DBA_JOBS* there; STOP_JOB vs. “killing the session,” and so on.
The day-to-day result is operational friction: different queries for the same question, parallel scripts for equivalent operations, and an unnecessary learning curve for simple tasks such as seeing what is running, enabling/disabling, and pausing a batch of jobs for a maintenance window.
This solution was born from exactly that scenario. The goal is to offer a single, transparent point to inventory, monitor, and operate both mechanisms without complexity.
You query one consolidated view (inventory and execution) and run one single package for common actions, whether it is a named Scheduler job or a numeric DBMS_JOB.
2) What DBMS_SCHEDULER and DBMS_JOB are
DBMS_SCHEDULER (the modern mechanism)
Introduced to replace DBMS_JOB, DBMS_SCHEDULER offers a rich, modular architecture:
- Separate Jobs, Programs, and Schedules, enabling reuse and governance.
- Chains (flows with dependencies), Windows, and Job Classes.
- Expressive scheduling via
repeat_interval(calendar expressions). - Controlled stop (
STOP_JOB), detailed logging, prioritization, and integration with Resource Manager. - A broad dictionary (
DBA_SCHEDULER_JOBS,DBA_SCHEDULER_RUNNING_JOBS, etc.).
In short: more features, traceability, and fine-grained control. It is the recommended standard for new routines.
DBMS_JOB (the legacy mechanism)
DBMS_JOB is simpler and more direct:
- Each job has a number (e.g., 128), a WHAT command (the PL/SQL to run), a NEXT_DATE, and an INTERVAL (string).
- Availability is represented by
BROKEN = 'Y'|'N'instead ofENABLED. - It does not have a native command to stop a running execution; in practice, you terminate the session that is executing the job.
- A compact dictionary (
DBA_JOBS,DBA_JOBS_RUNNING).
Although less flexible, it is common for older environments to still keep stable routines running under DBMS_JOB.
Advantages of using this solution
1. A single, coherent interface
- Consolidated views for inventory (
JOB_ADMIN_ALL_JOBS[_V]) and execution (JOB_ADMIN_RUNNING[_V]) that merge Scheduler and DBMS_JOB. - Homogeneous columns:
enabledalways as TRUE/FALSE, with dates and intervals formatted in the “_V” versions.
2. Immediate productivity
- A single query answers “what do I have?”, “when does it run?”, “what is running and for how long?”.
- The operator does not need to remember whether a job is Scheduler or DBMS_JOB to check status or take action.
3. Simple, safe operation
- Enable/disable through a single procedure (
enable_job/disable_job), passing a name (Scheduler) or a number (DBMS_JOB). - Graceful stop: for Scheduler it uses
STOP_JOB(force => TRUE); for DBMS_JOB, it terminates the running session before changing the state (RAC-aware). - Smart batching (
set_jobs_by_pattern): apply an action to a set of jobs viaLIKE, choosing the type (Scheduler/DBMS_JOB/ANY) and whether active jobs should be stopped.
4. Observability and standardization
- The output of
list_jobsandlist_running_jobsis clean and easy to read, integrating both technologies with the same layout. - It makes audits, health checks, and operational reports easier with fewer scripts.
5. Simplified governance
- A single role (
JOBDBMSSCHEDULERALL) and public synonyms: standardizes consumption across teams and tools. AUTHID DEFINER: users do not need DBA privileges: being granted the role is enough.
6. Idempotence and low deployment friction
CREATE OR REPLACEon every object plus defensive checks: rerunning it reinstalls.- RAC-compatible and able to run in a PDB (when applicable).
7. Lower operational risk
- Clear messages and validations ensure that “job not found” or “ambiguous name across owners” cases are handled with explanatory errors.
- During maintenance,
p_stop_running => TRUEreduces inconsistencies by pausing an entire batch in a controlled way.
8. A gateway to modernization
- By providing unified visibility and control, the solution makes gradual migrations from DBMS_JOB to DBMS_SCHEDULER easier, without disrupting day-to-day operations.
Download the pkg_job_admin installer from the link below and enable unified Oracle job management.
Oracle job administration in one place: installing and using pkg_job_admin
[ORCL.oracle@furushimait_labs ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Wed Sep 10 14:52:51 2025
Version 19.20.0.0.0
Copyright (c) 1982, 2022, Oracle. All rights reserved.
Connected to:
Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production
Version 19.20.0.0.0
SQL> @job_admin_setup_completo.sql
═════════════════════════════════════════════════════════════════════════════════════════════
Iniciando job_admin_setup_completo.sql
═════════════════════════════════════════════════════════════════════════════════════════════
Owner atual: SYS
PL/SQL procedure successfully completed.
── 1) Criando/Atualizando Views Consolidadas …
View created.
View created.
View created.
View created.
✓ Views criadas/atualizadas com sucesso.
── 2) Criando/Atualizando Pacote (SPEC) …
Package created.
No errors.
── 3) Criando/Atualizando Pacote (BODY) …
Package body created.
No errors.
✓ Pacote criado/atualizado com sucesso.
── 4) Segurança: ROLE, Grants e Sinônimos Públicos …
Role JOBDBMSSCHEDULERALL já existente.
PL/SQL procedure successfully completed.
Grant succeeded.
Grant succeeded.
Grant succeeded.
Grant succeeded.
Grant succeeded.
Sinônimos públicos criados/atualizados.
PL/SQL procedure successfully completed.
✓ Segurança configurada (ROLE + grants + sinônimos públicos).
── 5) Auto-Validação (não intrusiva) …
Pacote PKG_JOB_ADMIN sem erros de compilação.
PL/SQL procedure successfully completed.
Views acessíveis: JOB_ADMIN_ALL_JOBS e JOB_ADMIN_RUNNING OK.
PL/SQL procedure successfully completed.
── 6) Exemplos de Uso para referência …
-- Inventário:
BEGIN
pkg_job_admin.list_jobs; -- todos os jobs
pkg_job_admin.list_jobs('DEMOAPP'); -- por owner
pkg_job_admin.list_jobs(p_like => 'JOB_%'); -- por padrão (LIKE)
END
/
-- Em execução agora:
BEGIN
pkg_job_admin.list_running_jobs; -- tudo
pkg_job_admin.list_running_jobs('DEMOAPP'); -- por owner
pkg_job_admin.list_running_jobs(p_like => 'SYNC_%'); -- por padrão (LIKE)
END
/
-- Operações pontuais:
-- SCHEDULER (por nome; owner opcional se único no banco)
-- BEGIN
-- pkg_job_admin.disable_job('DEMOAPP.JOB_ATUALIZA_INDICES', p_stop_running => TRUE)
-- pkg_job_admin.enable_job ('DEMOAPP.JOB_ATUALIZA_INDICES')
-- END
-- /
-- DBMS_JOB (por número; owner apenas para validar pertinência quando desejar)
-- BEGIN
-- pkg_job_admin.disable_job('128', p_owner => 'SYS', p_stop_running => TRUE)
-- pkg_job_admin.enable_job ('128', p_owner => 'SYS')
-- END
-- /
-- Lote por padrão (por tipo):
-- BEGIN
-- pkg_job_admin.set_jobs_by_pattern(
-- p_name_like => 'JOB_SYNC_%',
-- p_enable => FALSE,
-- p_owner => 'DEMOAPP',
-- p_type => pkg_job_admin.c_type_scheduler, -- SCHEDULER | DBMS_JOB | ANY
-- p_stop_running => TRUE
-- )
-- END
-- /
-- Visões consolidadas:
-- SELECT * FROM job_admin_all_jobs_v ORDER BY owner, job_type, job_name
-- SELECT * FROM job_admin_running_v ORDER BY running_instance, job_type, job_name
═════════════════════════════════════════════════════════════════════════════════════════════
Conclusão: job_admin_setup_completo.sql executado.
Para conceder a ROLE a um usuário final, utilize:
GRANT JOBDBMSSCHEDULERALL TO nome_do_usuario
═════════════════════════════════════════════════════════════════════════════════════════════
What the script creates
Data objects (views)
JOB_ADMIN_ALL_JOBS: Unified inventory (SCHEDULER + DBMS_JOB).JOB_ADMIN_RUNNING: Unified view of current execution (SCHEDULER + DBMS_JOB).JOB_ADMIN_ALL_JOBS_V: “Friendly” version of the inventory (formatted dates and intervals).JOB_ADMIN_RUNNING_V: “Friendly” version of the execution view (formatted intervals).
API (package)
PKG_JOB_ADMIN: Procedures to list, enable/disable, and control batches.list_jobs(p_owner, p_like)list_running_jobs(p_owner, p_like)set_job_enabled(p_job_identifier, p_enable, p_owner, p_stop_running)enable_job(...)/disable_job(...)set_jobs_by_pattern(p_name_like, p_enable, p_owner, p_type, p_stop_running)- Constants:
c_type_scheduler,c_type_dbms_job,c_type_any
Consolidated inventory, ready for reporting
SELECT
owner,
job_type,
job_name,
enabled,
state,
next_run_date
FROM
job_admin_all_jobs_v
ORDER BY
owner,
job_type,
job_name;
Current execution (what is running right now)
SELECT
owner,
job_type,
job_name,
running_instance,
elapsed_time
FROM
job_admin_running_v
ORDER BY
running_instance,
job_type,
job_name;
Enable/disable individually
-- DBMS_SCHEDULER por nome (com owner)
BEGIN
pkg_job_admin.disable_job('DEMOAPP.JOB_XPTO_ETL_DIARIO', p_stop_running => TRUE);
pkg_job_admin.enable_job ('DEMOAPP.JOB_XPTO_ETL_DIARIO');
END;
/
-- DBMS_JOB por número (com validação de owner opcional)
BEGIN
pkg_job_admin.disable_job('128', p_owner => 'SYS', p_stop_running => TRUE);
pkg_job_admin.enable_job ('128', p_owner => 'SYS');
END;
/Enable/disable jobs in batch
BEGIN
pkg_job_admin.set_jobs_by_pattern(
p_name_like => 'JOB_XPTO_%',
p_enable => FALSE, -- desativar todos que casem com o padrão
p_owner => 'DEMOAPP', -- opcional
p_type => pkg_job_admin.c_type_scheduler, -- QUALQUER TIPO : SCHEDULER | DBMS_JOB | ANY
p_stop_running => TRUE
);
END;
/Which jobs exist and when will they run?
SELECT owner, job_type, job_name, enabled, state, next_run_date
FROM job_admin_all_jobs_v
ORDER BY owner, job_type, job_name;
-- O que observar
-- • job_type: distingue SCHEDULER vs DBMS_JOB.
-- • enabled: “TRUE/FALSE” consolidado para ambos.
-- • state: útil para SCHEDULER (ex.: SCHEDULED, DISABLED).Which jobs contain the word ‘XPTO’ in their name or command?
SELECT owner, job_type, job_name, enabled, job_action
FROM job_admin_all_jobs
WHERE UPPER(job_name) LIKE '%XPTO%'
OR UPPER(job_action) LIKE '%XPTO%'
ORDER BY owner, job_name;What is the next scheduled run for the jobs in my application schema?
SELECT job_name, enabled, state, next_run_date
FROM job_admin_all_jobs_v
WHERE owner = 'DEMOAPP'
ORDER BY job_name;What is running right now, and for how long?
SELECT owner, job_type, job_name, running_instance, elapsed_time
FROM job_admin_running_v
ORDER BY running_instance, job_type, job_name;Now let’s check whether the job JOB_XPTO_ETL_DIARIO is running and for how long
SELECT owner, job_type, job_name, elapsed_time
FROM job_admin_running_v
WHERE job_name = 'JOB_XPTO_ETL_DIARIO';
-- • Se vier linha, o job está ativo; elapsed_time mostra a duração no formato DD HH:MI:SS.Which jobs are disabled, for a quick review?
SELECT owner, job_type, job_name, enabled
FROM job_admin_all_jobs_v
WHERE enabled = 'FALSE'
ORDER BY owner, job_type, job_name;How to use the package (step-by-step examples)
All the examples assume you have the JOBDBMSSCHEDULERALL role.
Use the public synonyms (pkg_job_admin); there is no need to prefix with the schema.
-- Inventário
BEGIN
pkg_job_admin.list_jobs; -- Listar TUDO!
pkg_job_admin.list_jobs('DEMOAPP'); -- Procurar pelo OWNER
pkg_job_admin.list_jobs(p_like => 'JOB_%'); -- Busca por jobs cujo nome contenha o padrão informado (equivalente ao LIKE).
END;
/
--- OUTPUT :
=== JOBS (SCHEDULER) ===
DEMOAPP.JOB_XPTO_ETL_DIARIO | enabled=TRUE | state=SCHEDULED | next=2025-09-27 01:00:00 | action=BEGIN pkg_etl.run_daily; END;
DEMOAPP.JOB_SYNC_CLIENTES | enabled=FALSE | state=DISABLED | next=- | action=BEGIN sync_clientes(); END;
=== JOBS (DBMS_JOB) ===
DEMOAPP.128 | enabled=TRUE | next=2025-09-11 03:00:00 | what=BEGIN antiga_rotina(); END;Execution (what is running) with a guided read
-- Agora vamos ver se o job XPTO está rodando e há quanto tempo
BEGIN
pkg_job_admin.list_running_jobs(p_like => 'JOB_XPTO_%');
END;
/
--- OUTPUT :
=== RUNNING (SCHEDULER) ===
DEMOAPP.JOB_XPTO_ETL_DIARIO | sid=123 | inst=1 | elapsed=00 00:07:32 | cpu=00 00:02:10
=== RUNNING (DBMS_JOB) ===
-- (vazio, se nada estiver executando)One-off operations: enable/disable
-- DBMS_SCHEDULER por nome (owner informado, mais explícito):
BEGIN
-- desativar e forçar parada se estiver rodando
pkg_job_admin.disable_job('DEMOAPP.JOB_XPTO_ETL_DIARIO', p_stop_running => TRUE);
-- reativar
pkg_job_admin.enable_job ('DEMOAPP.JOB_XPTO_ETL_DIARIO');
END;
/
--- DBMS_JOB por número (owner opcional, útil para validar pertinência):
BEGIN
-- desativar e forçar parada se estiver rodando
pkg_job_admin.disable_job('128', p_owner => 'DEMOAPP', p_stop_running => TRUE);
-- reativar
pkg_job_admin.enable_job ('128', p_owner => 'DEMOAPP');
END;
/
-- O que acontece por trás:
-- • SCHEDULER: STOP_JOB(..., force => TRUE) (se p_stop_running=>TRUE), seguido de DISABLE/ENABLE.
-- • DBMS_JOB: encerra sessão (se ativa) e marca BROKEN (NOT p_enable).
Batch operations: disable all “JOB_XPTO_%” SCHEDULER jobs
-- Cenário: janela de manutenção requer pausar rotinas XPTO do schema de aplicação.
--- Desativar
BEGIN
pkg_job_admin.set_jobs_by_pattern(
p_name_like => 'JOB_XPTO_%',
p_enable => FALSE, -- desativar
p_owner => 'DEMOAPP',
p_type => pkg_job_admin.c_type_scheduler,
p_stop_running => TRUE -- encerrar active session job
);
END;
/
--- Reativar
BEGIN
pkg_job_admin.set_jobs_by_pattern(
p_name_like => 'JOB_XPTO_%',
p_enable => TRUE, -- reativar
p_owner => 'DEMOAPP',
p_type => pkg_job_admin.c_type_scheduler
);
END;
/
Analyze the job ‘JOB_XPTO_ETL_DIARIO’ specifically
-- 1. Está presente? Quando roda?
SELECT *
FROM job_admin_all_jobs_v
WHERE owner = 'DEMOAPP' AND job_name = 'JOB_XPTO_ETL_DIARIO';
-- 2. Está executando agora? Há quanto tempo?
SELECT running_instance, elapsed_time
FROM job_admin_running_v
WHERE owner = 'DEMOAPP' AND job_name = 'JOB_XPTO_ETL_DIARIO';
-- 3. Pausar com segurança (parar se ativo, depois desabilitar)
BEGIN
pkg_job_admin.disable_job('DEMOAPP.JOB_XPTO_ETL_DIARIO', p_stop_running => TRUE);
END;
/
-- 4. Reativar
BEGIN
pkg_job_admin.enable_job('DEMOAPP.JOB_XPTO_ETL_DIARIO');
END;
/
What is this solution good for?
Oracle environments often run two scheduling mechanisms side by side: DBMS_SCHEDULER (modern) and DBMS_JOB (legacy). When we need to inventory, monitor, enable/disable, or batch-manage both types, the typical experience is asymmetric and scattered.
This project delivers a single, consistent interface to handle both worlds:
- Consolidated views for inventory and execution.
- A PL/SQL package with simple, readable commands for one-off and batch operations.
- A role and public synonyms to standardize consumption safely.
Below is the full source code of the pkg_job_admin package
-- =================================================================================================
-- job_admin_setup_completo.sql
-- Administração unificada de jobs no Oracle Database (DBMS_SCHEDULER e DBMS_JOB)
-- Autor: Carlos Furushima, Furushima IT
-- Direitos Autorais: Este script é propriedade intelectual de Furushima IT. Todos os direitos reservados.
--
-- OBJETIVO
-- --------
-- Fornecer uma interface única, consistente e profissional para:
-- • Inventariar jobs do SCHEDULER e do DBMS_JOB em visões consolidadas;
-- • Consultar jobs em execução (tempo decorrido e sessão, quando aplicável);
-- • Habilitar/Desabilitar jobs individualmente (por nome ou número);
-- • Habilitar/Desabilitar em lote por padrão de nome;
-- • Padronizar o consumo por meio de uma ROLE e sinônimos públicos.
--
-- O QUE É CRIADO
-- --------------
-- Views:
-- - JOB_ADMIN_ALL_JOBS : inventário unificado (SCHEDULER + DBMS_JOB)
-- - JOB_ADMIN_RUNNING : execução unificada (SCHEDULER + DBMS_JOB)
-- - JOB_ADMIN_ALL_JOBS_V : inventário formatado para leitura humana
-- - JOB_ADMIN_RUNNING_V : execução formatada para leitura humana
--
-- Pacote:
-- - PKG_JOB_ADMIN : utilitários de listagem e (des)ativação unificada
--
-- Segurança e Acesso:
-- - ROLE JOBDBMSSCHEDULERALL com grants de SELECT/EXECUTE
-- - Sinônimos públicos para facilitar o uso por quem tiver a ROLE
--
-- PRÉ-REQUISITOS
-- --------------
-- • Executar com um usuário com privilégios para consultar dicionários DBA_* e GV$* e criar objetos.
-- • O pacote é AUTHID DEFINER (permissões do dono do pacote). Usuários finais só precisam da ROLE.
--
-- USO TÍPICO
-- ----------
-- -- Inventário:
-- BEGIN
-- pkg_job_admin.list_jobs; -- tudo
-- pkg_job_admin.list_jobs('DEMOAPP'); -- por owner
-- pkg_job_admin.list_jobs(p_like => 'JOB_%'); -- por padrão (LIKE)
-- END;
-- /
--
-- -- Executando agora:
-- BEGIN
-- pkg_job_admin.list_running_jobs; -- tudo
-- pkg_job_admin.list_running_jobs('DEMOAPP'); -- por owner
-- pkg_job_admin.list_running_jobs(p_like => 'SYNC_%'); -- por padrão (LIKE)
-- END;
-- /
--
-- -- Operações pontuais:
-- -- SCHEDULER (identificador por nome, owner opcional se único no banco)
-- -- BEGIN
-- -- pkg_job_admin.disable_job('DEMOAPP.JOB_ATUALIZA_INDICES', p_stop_running => TRUE);
-- -- pkg_job_admin.enable_job ('DEMOAPP.JOB_ATUALIZA_INDICES');
-- -- END;
-- -- /
-- --
-- -- DBMS_JOB (identificador numérico; owner opcional apenas para validar pertinência)
-- -- BEGIN
-- -- pkg_job_admin.disable_job('128', p_owner => 'SYS', p_stop_running => TRUE);
-- -- pkg_job_admin.enable_job ('128', p_owner => 'SYS');
-- -- END;
-- -- /
--
-- -- Lote por padrão (por tipo):
-- -- BEGIN
-- -- pkg_job_admin.set_jobs_by_pattern(
-- -- p_name_like => 'JOB_SYNC_%',
-- -- p_enable => FALSE, -- desativar
-- -- p_owner => 'DEMOAPP', -- opcional
-- -- p_type => pkg_job_admin.c_type_scheduler, -- SCHEDULER | DBMS_JOB | ANY
-- -- p_stop_running => TRUE
-- -- );
-- -- END;
-- -- /
--
-- DICAS
-- -----
-- • O script é idempotente (CREATE OR REPLACE; checagens seguras). Pode ser executado mais de uma vez.
-- • Saída “limpa”: mensagens organizadas por PROMPT/DBMS_OUTPUT para auditoria e documentação.
-- =================================================================================================
SET FEEDBACK ON
SET SERVEROUTPUT ON SIZE UNLIMITED
SET VERIFY OFF
PROMPT
PROMPT ═════════════════════════════════════════════════════════════════════════════════════════════
PROMPT Iniciando job_admin_setup_completo.sql
PROMPT ═════════════════════════════════════════════════════════════════════════════════════════════
-- -----------------------------------------------------------------------------------------------
-- 0) CONTEXTO: Mostra o usuário (owner) sob o qual os objetos serão criados
-- -----------------------------------------------------------------------------------------------
DECLARE
l_user VARCHAR2(128) := USER;
BEGIN
DBMS_OUTPUT.PUT_LINE('Owner atual: '||l_user);
END;
/
PROMPT
PROMPT ── 1) Criando/Atualizando Views Consolidadas …
-- ===============================================================================================
-- 1.1) JOB_ADMIN_ALL_JOBS
-- Consolida em uma única visão os jobs do DBMS_SCHEDULER e do DBMS_JOB.
-- Observações de tipos:
-- • next_run_date / last_start_date: TIMESTAMP WITH TIME ZONE (SCHEDULER) x DATE (DBMS_JOB)
-- -> o Oracle promove DATE para TIMESTAMP durante o UNION ALL (sem perda de funcionalidade).
-- • last_run_duration: INTERVAL no SCHEDULER; CAST de NULL para INTERVAL no DBMS_JOB.
-- • job_action / repeat_interval: normalizados para VARCHAR2 (até 4000) no DBMS_JOB.
-- ===============================================================================================
CREATE OR REPLACE VIEW job_admin_all_jobs AS
SELECT owner,
job_name,
'SCHEDULER' AS job_type,
CASE WHEN enabled = 'TRUE' THEN 'TRUE' ELSE 'FALSE' END AS enabled,
state,
next_run_date, -- TIMESTAMP WITH TIME ZONE
last_start_date, -- TIMESTAMP WITH TIME ZONE
last_run_duration, -- INTERVAL DAY TO SECOND
job_action, -- VARCHAR2/CLOB (na maioria dos casos, até 4000)
repeat_interval -- VARCHAR2
FROM dba_scheduler_jobs
UNION ALL
SELECT schema_user AS owner,
TO_CHAR(job) AS job_name,
'DBMS_JOB' AS job_type,
CASE broken WHEN 'Y' THEN 'FALSE' ELSE 'TRUE' END AS enabled,
CAST(NULL AS VARCHAR2(30)) AS state,
next_date, -- DATE (promovido a TIMESTAMP no UNION)
last_date AS last_start_date, -- DATE
CAST(NULL AS INTERVAL DAY TO SECOND) AS last_run_duration,
SUBSTR(what, 4000) AS job_action, -- LONG -> VARCHAR2
SUBSTR(interval, 4000) AS repeat_interval -- LONG -> VARCHAR2
FROM dba_jobs
;
-- ===============================================================================================
-- 1.2) JOB_ADMIN_RUNNING
-- Consolida os jobs em execução. Para DBMS_JOB, calcula elapsed pelo logon_time da sessão.
-- Observações:
-- • cpu_used não se aplica ao DBMS_JOB; representa-se com NULL (cast para INTERVAL).
-- ===============================================================================================
CREATE OR REPLACE VIEW job_admin_running AS
SELECT owner,
job_name,
'SCHEDULER' AS job_type,
session_id,
running_instance,
elapsed_time, -- INTERVAL
cpu_used -- INTERVAL
FROM dba_scheduler_running_jobs
UNION ALL
SELECT j.schema_user AS owner,
TO_CHAR(r.job) AS job_name,
'DBMS_JOB' AS job_type,
r.sid AS session_id,
s.inst_id AS running_instance,
NUMTODSINTERVAL(TRUNC((SYSDATE - s.logon_time)*86400),'SECOND') AS elapsed_time,
CAST(NULL AS INTERVAL DAY TO SECOND) AS cpu_used
FROM dba_jobs_running r
JOIN gv$session s ON s.sid = r.sid
JOIN dba_jobs j ON j.job = r.job
;
-- ===============================================================================================
-- 1.3) JOB_ADMIN_ALL_JOBS_V: Versão “amigável” (formatos para leitura humana)
-- ===============================================================================================
CREATE OR REPLACE VIEW job_admin_all_jobs_v AS
SELECT owner, job_name, job_type, enabled, state,
TO_CHAR(next_run_date,'YYYY-MM-DD HH24:MI:SS') AS next_run_date,
TO_CHAR(last_start_date,'YYYY-MM-DD HH24:MI:SS') AS last_start_date,
CASE WHEN last_run_duration IS NULL THEN '-' ELSE
EXTRACT(DAY FROM last_run_duration)||' '||
LPAD(EXTRACT(HOUR FROM last_run_duration),2,'0')||':'||
LPAD(EXTRACT(MINUTE FROM last_run_duration),2,'0')||':'||
LPAD(TRUNC(EXTRACT(SECOND FROM last_run_duration)),2,'0')
END AS last_run_duration,
job_action, repeat_interval
FROM job_admin_all_jobs
;
-- ===============================================================================================
-- 1.4) JOB_ADMIN_RUNNING_V: Versão “amigável” (formatos para leitura humana)
-- ===============================================================================================
CREATE OR REPLACE VIEW job_admin_running_v AS
SELECT owner, job_name, job_type, session_id, running_instance,
CASE WHEN elapsed_time IS NULL THEN '-' ELSE
EXTRACT(DAY FROM elapsed_time)||' '||
LPAD(EXTRACT(HOUR FROM elapsed_time),2,'0')||':'||
LPAD(EXTRACT(MINUTE FROM elapsed_time),2,'0')||':'||
LPAD(TRUNC(EXTRACT(SECOND FROM elapsed_time)),2,'0')
END AS elapsed_time,
CASE WHEN cpu_used IS NULL THEN '-' ELSE
EXTRACT(DAY FROM cpu_used)||' '||
LPAD(EXTRACT(HOUR FROM cpu_used),2,'0')||':'||
LPAD(EXTRACT(MINUTE FROM cpu_used),2,'0')||':'||
LPAD(TRUNC(EXTRACT(SECOND FROM cpu_used)),2,'0')
END AS cpu_used
FROM job_admin_running
;
PROMPT ✓ Views criadas/atualizadas com sucesso.
PROMPT
PROMPT ── 2) Criando/Atualizando Pacote (SPEC) …
-- =================================================================================================
-- 2) ESPECIFICAÇÃO DO PACOTE: PKG_JOB_ADMIN
-- Contém constantes de tipo e procedimentos públicos de listagem e (des)ativação unificada.
-- =================================================================================================
CREATE OR REPLACE PACKAGE pkg_job_admin AUTHID DEFINER AS
-- Constantes para filtro por tipo
c_type_scheduler CONSTANT VARCHAR2(11) := 'SCHEDULER';
c_type_dbms_job CONSTANT VARCHAR2(8) := 'DBMS_JOB';
c_type_any CONSTANT VARCHAR2(3) := 'ANY';
-- Listagem de jobs (inventário)
PROCEDURE list_jobs(
p_owner IN VARCHAR2 DEFAULT NULL, -- filtra por owner
p_like IN VARCHAR2 DEFAULT NULL -- filtra por padrão (LIKE)
);
-- Listagem de jobs em execução
PROCEDURE list_running_jobs(
p_owner IN VARCHAR2 DEFAULT NULL, -- filtra por owner
p_like IN VARCHAR2 DEFAULT NULL -- filtra por padrão (LIKE)
);
-- Habilita/Desabilita um job (identificador por nome SCHEDULER ou número DBMS_JOB)
PROCEDURE set_job_enabled(
p_job_identifier IN VARCHAR2, -- 'OWNER.JOB_NAME' | 'JOB_NAME' | '123' (DBMS_JOB)
p_enable IN BOOLEAN, -- TRUE = ENABLE; FALSE = DISABLE
p_owner IN VARCHAR2 DEFAULT NULL, -- para SCHEDULER sem owner único ou DBMS_JOB para validar owner
p_stop_running IN BOOLEAN DEFAULT FALSE -- encerra execução corrente (se houver)
);
-- Açúcares sintáticos (conveniências)
PROCEDURE enable_job(
p_job_identifier IN VARCHAR2,
p_owner IN VARCHAR2 DEFAULT NULL,
p_stop_running IN BOOLEAN DEFAULT FALSE
);
PROCEDURE disable_job(
p_job_identifier IN VARCHAR2,
p_owner IN VARCHAR2 DEFAULT NULL,
p_stop_running IN BOOLEAN DEFAULT TRUE
);
-- Habilita/Desabilita em lote por padrão de nome e tipo
PROCEDURE set_jobs_by_pattern(
p_name_like IN VARCHAR2, -- ex: 'JOB_SYNC_%'
p_enable IN BOOLEAN, -- TRUE/FALSE
p_owner IN VARCHAR2 DEFAULT NULL, -- opcional
p_type IN VARCHAR2 DEFAULT c_type_any, -- SCHEDULER | DBMS_JOB | ANY
p_stop_running IN BOOLEAN DEFAULT FALSE
);
END pkg_job_admin;
/
SHOW ERRORS
PROMPT
PROMPT ── 3) Criando/Atualizando Pacote (BODY) …
-- =================================================================================================
-- 3) CORPO DO PACOTE: PKG_JOB_ADMIN
-- Implementa utilitários de formatação, detecção de owner/instância, e operações de controle.
-- =================================================================================================
CREATE OR REPLACE PACKAGE BODY pkg_job_admin AS
-- ---------------------------------------------------------------------------------------------
-- Função auxiliar: formata INTERVAL DAY TO SECOND em 'DD HH24:MI:SS'
-- ---------------------------------------------------------------------------------------------
FUNCTION fmt_ds(p INTERVAL DAY TO SECOND) RETURN VARCHAR2 IS
l_day PLS_INTEGER; l_hour PLS_INTEGER; l_min PLS_INTEGER; l_sec PLS_INTEGER;
BEGIN
IF p IS NULL THEN RETURN '-'; END IF;
l_day := EXTRACT(DAY FROM p);
l_hour := EXTRACT(HOUR FROM p);
l_min := EXTRACT(MINUTE FROM p);
l_sec := TRUNC(EXTRACT(SECOND FROM p));
RETURN LPAD(l_day,2,'0')||' '||LPAD(l_hour,2,'0')||':'||LPAD(l_min,2,'0')||':'||LPAD(l_sec,2,'0');
END fmt_ds;
-- ---------------------------------------------------------------------------------------------
-- Função auxiliar: TO_CHAR seguro para datas que podem ser NULL (retorna '-' no NULL)
-- ---------------------------------------------------------------------------------------------
FUNCTION to_char_nvl(p_date DATE) RETURN VARCHAR2 IS
BEGIN
RETURN CASE WHEN p_date IS NULL THEN '-' ELSE TO_CHAR(p_date,'YYYY-MM-DD HH24:MI:SS') END;
END;
-- ---------------------------------------------------------------------------------------------
-- Monta o nome totalmente qualificado do job de SCHEDULER
-- ---------------------------------------------------------------------------------------------
FUNCTION sched_job_fqname(p_owner IN VARCHAR2, p_job_name IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN CASE WHEN p_owner IS NOT NULL THEN UPPER(p_owner)||'.'||UPPER(p_job_name) ELSE UPPER(p_job_name) END;
END;
-- ---------------------------------------------------------------------------------------------
-- Solicita parada de job SCHEDULER, se estiver em execução (silencioso em falhas)
-- ---------------------------------------------------------------------------------------------
PROCEDURE stop_scheduler_if_running(p_owner IN VARCHAR2, p_job_name IN VARCHAR2) IS
l_fq VARCHAR2(261) := sched_job_fqname(p_owner, p_job_name);
BEGIN
DBMS_SCHEDULER.STOP_JOB(job_name => l_fq, force => TRUE);
EXCEPTION
WHEN OTHERS THEN NULL;
END;
-- ---------------------------------------------------------------------------------------------
-- Encerra sessão de DBMS_JOB, se houver (suporte RAC com @inst_id)
-- ---------------------------------------------------------------------------------------------
PROCEDURE kill_dbms_job_session(p_job_id IN NUMBER) IS
l_sid NUMBER;
l_serial NUMBER;
l_inst NUMBER;
l_stmt VARCHAR2(200);
BEGIN
SELECT s.sid, s.serial#, s.inst_id
INTO l_sid, l_serial, l_inst
FROM dba_jobs_running r
JOIN gv$session s ON s.sid = r.sid
WHERE r.job = p_job_id
AND ROWNUM = 1;
l_stmt := 'ALTER SYSTEM KILL SESSION '''||l_sid||','||l_serial||
CASE WHEN l_inst IS NOT NULL THEN ',@'||l_inst ELSE NULL END||''' IMMEDIATE';
EXECUTE IMMEDIATE l_stmt;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
WHEN OTHERS THEN NULL;
END;
-- ---------------------------------------------------------------------------------------------
-- Resolve owner de job SCHEDULER quando usuário não informou p_owner
-- Lança erro se não encontrado ou se existir em múltiplos owners.
-- ---------------------------------------------------------------------------------------------
PROCEDURE resolve_scheduler(p_owner IN VARCHAR2, p_job_name IN VARCHAR2,
o_owner OUT VARCHAR2, o_job_name OUT VARCHAR2) IS
l_cnt INTEGER;
BEGIN
o_job_name := UPPER(p_job_name);
IF p_owner IS NOT NULL THEN o_owner := UPPER(p_owner); RETURN; END IF;
SELECT COUNT(DISTINCT owner) INTO l_cnt
FROM dba_scheduler_jobs
WHERE job_name = o_job_name;
IF l_cnt = 0 THEN
RAISE NO_DATA_FOUND;
ELSIF l_cnt > 1 THEN
RAISE_APPLICATION_ERROR(-20002,
'JOB_NAME existe em múltiplos owners. Informe p_owner. JOB_NAME='||o_job_name);
ELSE
SELECT owner INTO o_owner
FROM dba_scheduler_jobs
WHERE job_name = o_job_name
AND ROWNUM = 1;
END IF;
END resolve_scheduler;
-- ---------------------------------------------------------------------------------------------
-- Listagem: inventário unificado
-- ---------------------------------------------------------------------------------------------
PROCEDURE list_jobs(p_owner IN VARCHAR2 DEFAULT NULL, p_like IN VARCHAR2 DEFAULT NULL) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('=== JOBS (SCHEDULER) ===');
FOR r IN (
SELECT owner, job_name, enabled, state, next_run_date, job_action
FROM dba_scheduler_jobs
WHERE (p_owner IS NULL OR owner = UPPER(p_owner))
AND (p_like IS NULL OR job_name LIKE UPPER(p_like))
ORDER BY owner, job_name
) LOOP
DBMS_OUTPUT.PUT_LINE(r.owner||'.'||r.job_name||
' | enabled='||r.enabled||
' | state='||NVL(r.state,'-')||
' | next='||to_char_nvl(CAST(r.next_run_date AS DATE))||
' | action='||SUBSTR(r.job_action,1,60));
END LOOP;
DBMS_OUTPUT.PUT_LINE(CHR(10)||'=== JOBS (DBMS_JOB) ===');
FOR r IN (
SELECT schema_user AS owner, job AS job_id, DECODE(broken,'Y','FALSE','TRUE') AS enabled,
next_date, what
FROM dba_jobs
WHERE (p_owner IS NULL OR schema_user = UPPER(p_owner))
AND (p_like IS NULL OR TO_CHAR(job) LIKE p_like OR UPPER(what) LIKE UPPER(p_like))
ORDER BY schema_user, job
) LOOP
DBMS_OUTPUT.PUT_LINE(r.owner||'.'||r.job_id||
' | enabled='||r.enabled||
' | next='||to_char_nvl(r.next_date)||
' | what='||SUBSTR(r.what,1,60));
END LOOP;
END list_jobs;
-- ---------------------------------------------------------------------------------------------
-- Listagem: execução unificada
-- ---------------------------------------------------------------------------------------------
PROCEDURE list_running_jobs(p_owner IN VARCHAR2 DEFAULT NULL, p_like IN VARCHAR2 DEFAULT NULL) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('=== RUNNING (SCHEDULER) ===');
FOR r IN (
SELECT owner, job_name, session_id, running_instance, elapsed_time, cpu_used
FROM dba_scheduler_running_jobs
WHERE (p_owner IS NULL OR owner = UPPER(p_owner))
AND (p_like IS NULL OR job_name LIKE UPPER(p_like))
ORDER BY running_instance, job_name
) LOOP
DBMS_OUTPUT.PUT_LINE(r.owner||'.'||r.job_name||
' | sid='||r.session_id||
' | inst='||r.running_instance||
' | elapsed='||fmt_ds(r.elapsed_time)||
' | cpu='||fmt_ds(r.cpu_used));
END LOOP;
DBMS_OUTPUT.PUT_LINE(CHR(10)||'=== RUNNING (DBMS_JOB) ===');
FOR r IN (
SELECT j.schema_user AS owner, r.job AS job_id, s.sid, s.serial#,
s.inst_id AS running_instance,
NUMTODSINTERVAL(TRUNC((SYSDATE - s.logon_time)*86400),'SECOND') AS elapsed_time,
j.what
FROM dba_jobs_running r
JOIN gv$session s ON s.sid = r.sid
JOIN dba_jobs j ON j.job = r.job
WHERE (p_owner IS NULL OR j.schema_user = UPPER(p_owner))
AND (p_like IS NULL OR TO_CHAR(r.job) LIKE p_like OR UPPER(j.what) LIKE UPPER(p_like))
ORDER BY running_instance, job_id
) LOOP
DBMS_OUTPUT.PUT_LINE(r.owner||'.'||r.job_id||
' | sid='||r.sid||','||r.serial#||
' | inst='||r.running_instance||
' | elapsed='||fmt_ds(r.elapsed_time));
END LOOP;
END list_running_jobs;
-- ---------------------------------------------------------------------------------------------
-- Núcleo: habilita/desabilita por identificador (nome SCHEDULER ou número DBMS_JOB)
-- ---------------------------------------------------------------------------------------------
PROCEDURE set_job_enabled(
p_job_identifier IN VARCHAR2,
p_enable IN BOOLEAN,
p_owner IN VARCHAR2 DEFAULT NULL,
p_stop_running IN BOOLEAN DEFAULT FALSE
) IS
l_owner VARCHAR2(128);
l_job_name VARCHAR2(128);
l_job_id NUMBER;
BEGIN
-- 1) Tentar SCHEDULER (nome)
BEGIN
IF REGEXP_LIKE(p_job_identifier,'^\d+$') THEN RAISE NO_DATA_FOUND; END IF;
IF INSTR(p_job_identifier,'.') > 0 THEN
l_owner := UPPER(REGEXP_SUBSTR(p_job_identifier,'^([^\.]+)'));
l_job_name := UPPER(REGEXP_SUBSTR(p_job_identifier,'\.([^\.]+)$',1,1,NULL,1));
ELSE
l_job_name := UPPER(p_job_identifier);
resolve_scheduler(p_owner, l_job_name, l_owner, l_job_name);
END IF;
-- valida existência
DECLARE l_dummy PLS_INTEGER;
BEGIN
SELECT 1 INTO l_dummy
FROM dba_scheduler_jobs
WHERE owner = l_owner AND job_name = l_job_name AND ROWNUM = 1;
END;
IF p_stop_running THEN
stop_scheduler_if_running(l_owner, l_job_name);
END IF;
IF p_enable THEN
DBMS_SCHEDULER.ENABLE( sched_job_fqname(l_owner, l_job_name) );
ELSE
DBMS_SCHEDULER.DISABLE( sched_job_fqname(l_owner, l_job_name) );
END IF;
DBMS_OUTPUT.PUT_LINE('OK (SCHEDULER) '||
sched_job_fqname(l_owner,l_job_name)||' => '||
CASE WHEN p_enable THEN 'ENABLED' ELSE 'DISABLED' END);
RETURN;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL; -- não era scheduler; tentar DBMS_JOB
END;
-- 2) Tentar DBMS_JOB (número)
BEGIN
l_job_id := TO_NUMBER(TRIM(p_job_identifier));
-- valida existência (restringe owner se informado)
DECLARE l_dummy2 PLS_INTEGER;
BEGIN
SELECT 1 INTO l_dummy2
FROM dba_jobs
WHERE job = l_job_id
AND (p_owner IS NULL OR schema_user = UPPER(p_owner))
AND ROWNUM = 1;
END;
IF p_stop_running THEN
kill_dbms_job_session(l_job_id);
END IF;
DBMS_JOB.BROKEN(l_job_id, NOT p_enable);
DBMS_OUTPUT.PUT_LINE('OK (DBMS_JOB) '||l_job_id||' => '||
CASE WHEN p_enable THEN 'ENABLED' ELSE 'DISABLED' END);
RETURN;
EXCEPTION
WHEN VALUE_ERROR THEN NULL;
WHEN INVALID_NUMBER THEN NULL;
WHEN NO_DATA_FOUND THEN NULL;
END;
-- 3) Não encontrado em nenhuma modalidade
RAISE_APPLICATION_ERROR(-20001,
'Job não encontrado como SCHEDULER (por nome) nem DBMS_JOB (por número): '||p_job_identifier);
END set_job_enabled;
-- Açúcares sintáticos
PROCEDURE enable_job(
p_job_identifier IN VARCHAR2,
p_owner IN VARCHAR2 DEFAULT NULL,
p_stop_running IN BOOLEAN DEFAULT FALSE
) IS
BEGIN
set_job_enabled(p_job_identifier => p_job_identifier,
p_enable => TRUE,
p_owner => p_owner,
p_stop_running => p_stop_running);
END;
PROCEDURE disable_job(
p_job_identifier IN VARCHAR2,
p_owner IN VARCHAR2 DEFAULT NULL,
p_stop_running IN BOOLEAN DEFAULT TRUE
) IS
BEGIN
set_job_enabled(p_job_identifier => p_job_identifier,
p_enable => FALSE,
p_owner => p_owner,
p_stop_running => p_stop_running);
END;
-- ---------------------------------------------------------------------------------------------
-- Habilita/Desabilita em lote por padrão (LIKE) e, opcionalmente, por tipo
-- ---------------------------------------------------------------------------------------------
PROCEDURE set_jobs_by_pattern(
p_name_like IN VARCHAR2,
p_enable IN BOOLEAN,
p_owner IN VARCHAR2 DEFAULT NULL,
p_type IN VARCHAR2 DEFAULT c_type_any,
p_stop_running IN BOOLEAN DEFAULT FALSE
) IS
BEGIN
-- SCHEDULER
IF UPPER(p_type) IN (c_type_any, c_type_scheduler) THEN
FOR r IN (
SELECT owner, job_name
FROM dba_scheduler_jobs
WHERE (p_owner IS NULL OR owner = UPPER(p_owner))
AND job_name LIKE UPPER(p_name_like)
) LOOP
set_job_enabled(r.owner||'.'||r.job_name, p_enable, NULL, p_stop_running);
END LOOP;
END IF;
-- DBMS_JOB
IF UPPER(p_type) IN (c_type_any, c_type_dbms_job) THEN
FOR r IN (
SELECT schema_user AS owner, job
FROM dba_jobs
WHERE (p_owner IS NULL OR schema_user = UPPER(p_owner))
AND (TO_CHAR(job) LIKE p_name_like OR UPPER(what) LIKE UPPER(p_name_like))
) LOOP
set_job_enabled(TO_CHAR(r.job), p_enable, r.owner, p_stop_running);
END LOOP;
END IF;
END set_jobs_by_pattern;
END pkg_job_admin;
/
SHOW ERRORS
PROMPT ✓ Pacote criado/atualizado com sucesso.
PROMPT
PROMPT ── 4) Segurança: ROLE, Grants e Sinônimos Públicos …
-- =================================================================================================
-- 4.1) ROLE: criada apenas se não existir
-- =================================================================================================
DECLARE
l_cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO l_cnt FROM dba_roles WHERE role = 'JOBDBMSSCHEDULERALL';
IF l_cnt = 0 THEN
EXECUTE IMMEDIATE 'CREATE ROLE JOBDBMSSCHEDULERALL';
DBMS_OUTPUT.PUT_LINE('Role JOBDBMSSCHEDULERALL criada.');
ELSE
DBMS_OUTPUT.PUT_LINE('Role JOBDBMSSCHEDULERALL já existente.');
END IF;
END;
/
-- =================================================================================================
-- 4.2) GRANTS: executar o pacote e consultar as views por meio da ROLE
-- =================================================================================================
GRANT EXECUTE ON pkg_job_admin TO JOBDBMSSCHEDULERALL;
GRANT SELECT ON job_admin_all_jobs TO JOBDBMSSCHEDULERALL;
GRANT SELECT ON job_admin_running TO JOBDBMSSCHEDULERALL;
GRANT SELECT ON job_admin_all_jobs_v TO JOBDBMSSCHEDULERALL;
GRANT SELECT ON job_admin_running_v TO JOBDBMSSCHEDULERALL;
-- =================================================================================================
-- 4.3) SINÔNIMOS PÚBLICOS: apontam para os objetos do OWNER atual
-- Observação: garantem uso uniforme via “public synonyms” para quem tiver a ROLE.
-- =================================================================================================
DECLARE
l_owner VARCHAR2(128) := USER;
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM job_admin_all_jobs FOR '||l_owner||'.job_admin_all_jobs';
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM job_admin_running FOR '||l_owner||'.job_admin_running';
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM job_admin_all_jobs_v FOR '||l_owner||'.job_admin_all_jobs_v';
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM job_admin_running_v FOR '||l_owner||'.job_admin_running_v';
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM pkg_job_admin FOR '||l_owner||'.pkg_job_admin';
DBMS_OUTPUT.PUT_LINE('Sinônimos públicos criados/atualizados.');
END;
/
PROMPT ✓ Segurança configurada (ROLE + grants + sinônimos públicos).
PROMPT
PROMPT ── 5) Auto-Validação (não intrusiva) …
-- =================================================================================================
-- 5.1) Verifica erros de compilação do pacote
-- =================================================================================================
DECLARE
l_errs INTEGER;
BEGIN
SELECT COUNT(*) INTO l_errs
FROM user_errors
WHERE name = 'PKG_JOB_ADMIN';
IF l_errs = 0 THEN
DBMS_OUTPUT.PUT_LINE('Pacote PKG_JOB_ADMIN sem erros de compilação.');
ELSE
DBMS_OUTPUT.PUT_LINE('ATENÇÃO: Encontrado(s) '||l_errs||' erro(s) em PKG_JOB_ADMIN:');
FOR r IN (
SELECT type, name, line, position, SUBSTR(text,1,200) AS text
FROM user_errors
WHERE name = 'PKG_JOB_ADMIN'
ORDER BY sequence
) LOOP
DBMS_OUTPUT.PUT_LINE(r.type||' '||r.name||' @'||r.line||':'||r.position||' - '||r.text);
END LOOP;
END IF;
END;
/
-- =================================================================================================
-- 5.2) Validação simples de acesso às views (sanidade)
-- =================================================================================================
DECLARE
l_all NUMBER; l_run NUMBER;
BEGIN
SELECT COUNT(*) INTO l_all FROM job_admin_all_jobs WHERE ROWNUM <= 1;
SELECT COUNT(*) INTO l_run FROM job_admin_running WHERE ROWNUM <= 1;
DBMS_OUTPUT.PUT_LINE('Views acessíveis: JOB_ADMIN_ALL_JOBS e JOB_ADMIN_RUNNING OK.');
END;
/
PROMPT
PROMPT ── 6) Exemplos de Uso (para referência; copiar/colar quando necessário) …
PROMPT
PROMPT -- Inventário:
PROMPT BEGIN
PROMPT pkg_job_admin.list_jobs; -- todos os jobs
PROMPT pkg_job_admin.list_jobs('DEMOAPP'); -- por owner
PROMPT pkg_job_admin.list_jobs(p_like => 'JOB_%'); -- por padrão (LIKE)
PROMPT END;
PROMPT /
PROMPT -- Em execução agora:
PROMPT BEGIN
PROMPT pkg_job_admin.list_running_jobs; -- tudo
PROMPT pkg_job_admin.list_running_jobs('DEMOAPP'); -- por owner
PROMPT pkg_job_admin.list_running_jobs(p_like => 'SYNC_%'); -- por padrão (LIKE)
PROMPT END;
PROMPT /
PROMPT -- Operações pontuais:
PROMPT -- SCHEDULER (por nome; owner opcional se único no banco)
PROMPT -- BEGIN
PROMPT -- pkg_job_admin.disable_job('DEMOAPP.JOB_ATUALIZA_INDICES', p_stop_running => TRUE);
PROMPT -- pkg_job_admin.enable_job ('DEMOAPP.JOB_ATUALIZA_INDICES');
PROMPT -- END;
PROMPT -- /
PROMPT -- DBMS_JOB (por número; owner apenas para validar pertinência quando desejar)
PROMPT -- BEGIN
PROMPT -- pkg_job_admin.disable_job('128', p_owner => 'SYS', p_stop_running => TRUE);
PROMPT -- pkg_job_admin.enable_job ('128', p_owner => 'SYS');
PROMPT -- END;
PROMPT -- /
PROMPT -- Lote por padrão (por tipo):
PROMPT -- BEGIN
PROMPT -- pkg_job_admin.set_jobs_by_pattern(
PROMPT -- p_name_like => 'JOB_SYNC_%',
PROMPT -- p_enable => FALSE,
PROMPT -- p_owner => 'DEMOAPP',
PROMPT -- p_type => pkg_job_admin.c_type_scheduler, -- SCHEDULER | DBMS_JOB | ANY
PROMPT -- p_stop_running => TRUE
PROMPT -- );
PROMPT -- END;
PROMPT -- /
PROMPT -- Visões consolidadas:
PROMPT -- SELECT * FROM job_admin_all_jobs_v ORDER BY owner, job_type, job_name;
PROMPT -- SELECT * FROM job_admin_running_v ORDER BY running_instance, job_type, job_name;
PROMPT
PROMPT ═════════════════════════════════════════════════════════════════════════════════════════════
PROMPT Conclusão: job_admin_setup_completo.sql executado.
PROMPT Para conceder a ROLE a um usuário final, utilize:
PROMPT GRANT JOBDBMSSCHEDULERALL TO nome_do_usuario;
PROMPT ═════════════════════════════════════════════════════════════════════════════════════════════