Non vuoi guardare dual
affatto qui; certamente non sto tentando di inserire. Devi tenere traccia dei valori più alti e più bassi che hai visto durante l'iterazione del ciclo. basato su alcuni degli elementi di ename
che rappresentano le date Sono abbastanza sicuro che tu voglia che tutte le tue corrispondenze siano 0-9
, non 1-9
. Ti riferisci anche al nome del cursore mentre accedi ai suoi campi, invece del nome della variabile del record:
FOR List_ENAME_rec IN List_ENAME_cur loop
if REGEXP_LIKE(List_ENAME_rec.ENAME,'emp[-][0-9]{4}[_][0-9]{2}[_][0-9]{2}[_][0-9]{2}[_][0-9]{4}[_][G][1]') then
V_seq := substr(List_ENAME_rec.ename,5,4);
V_Year := substr(List_ENAME_rec.ename,10,2);
V_Month := substr(List_ENAME_rec.ename,13,2);
V_day := substr(List_ENAME_rec.ename,16,2);
if min_seq is null or V_seq < min_seq then
min_seq := v_seq;
end if;
if max_seq is null or V_seq > max_seq then
max_seq := v_seq;
end if;
end if;
end loop;
Con valori nella tabella di emp-1111_14_01_01_1111_G1
e emp-1115_14_02_02_1111_G1
, che riporta max_seq 1115 min_seq 1111
.
Se volessi davvero coinvolgere il duale potresti farlo all'interno del ciclo, invece del modello if/then/assign, ma non è necessario:
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Non ho idea di cosa farà la procedura; sembra non esserci alcuna relazione tra ciò che hai in test1
e i valori che stai trovando.
Tuttavia, non è necessario alcun PL/SQL per questo. Puoi ottenere i valori min/max da una semplice query:
select min(to_number(substr(ename, 5, 4))) as min_seq,
max(to_number(substr(ename, 5, 4))) as max_seq
from table1
where status = 2
and regexp_like(ename,
'emp[-][0-9]{4}[_][0-9]{2}[_][0-9]{2}[_][0-9]{2}[_][0-9]{4}[_][G][1]')
MIN_SEQ MAX_SEQ
---------- ----------
1111 1115
E puoi usarli per generare un elenco di tutti i valori in quell'intervallo:
with t as (
select min(to_number(substr(ename, 5, 4))) as min_seq,
max(to_number(substr(ename, 5, 4))) as max_seq
from table1
where status = 2
and regexp_like(ename,
'emp[-][0-9]{4}[_][0-9]{2}[_][0-9]{2}[_][0-9]{2}[_][0-9]{4}[_][G][1]')
)
select min_seq + level - 1 as seq
from t
connect by level <= (max_seq - min_seq) + 1;
SEQ
----------
1111
1112
1113
1114
1115
E un'espressione di tabella comune leggermente diversa per vedere quale di quelle non esiste nella tua tabella, che penso sia quello che stai cercando:
with t as (
select to_number(substr(ename, 5, 4)) as seq
from table1
where status = 2
and regexp_like(ename,
'emp[-][0-9]{4}[_][0-9]{2}[_][0-9]{2}[_][0-9]{2}[_][0-9]{4}[_][G][1]')
),
u as (
select min(seq) as min_seq,
max(seq) as max_seq
from t
),
v as (
select min_seq + level - 1 as seq
from u
connect by level <= (max_seq - min_seq) + 1
)
select v.seq as missing_seq
from v
left join t on t.seq = v.seq
where t.seq is null
order by v.seq;
MISSING_SEQ
-----------
1112
1113
1114
o se preferisci:
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Sulla base dei commenti, penso che tu voglia i valori mancanti per la sequenza per ogni combinazione degli altri elementi dell'ID (AA_MM_GG). Questo ti darà quella ripartizione:
with t as (
select to_number(substr(ename, 5, 4)) as seq,
substr(ename, 10, 2) as yy,
substr(ename, 13, 2) as mm,
substr(ename, 16, 2) as dd
from table1
where status = 2
and regexp_like(ename,
'emp[-][0-9]{4}[_][0-9]{2}[_][0-9]{2}[_][0-9]{2}[_][0-9]{4}[_][G][1]')
),
r (yy, mm, dd, seq, max_seq) as (
select yy, mm, dd, min(seq), max(seq)
from t
group by yy, mm, dd
union all
select yy, mm, dd, seq + 1, max_seq
from r
where seq + 1 <= max_seq
)
select yy, mm, dd, seq as missing_seq
from r
where not exists (
select 1 from t
where t.yy = r.yy
and t.mm = r.mm
and t.dd = r.dd
and t.seq = r.seq
)
order by yy, mm, dd, seq;
Con output come:
YY MM DD MISSING_SEQ
---- ---- ---- -------------
14 01 01 1112
14 01 01 1113
14 01 01 1114
14 02 02 1118
14 02 02 1120
14 02 03 1127
14 02 03 1128
Se vuoi cercare una data particolare, filtrala a freddo (o in t
o il primo ramo in r
), ma potresti anche modificare il modello regex per includere i valori fissi; quindi per cercare 14 06
lo schema sarebbe 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, Per esempio. Tuttavia è più difficile generalizzare, quindi un filtro (where t.yy = '14' and t.mm = '06'
potrebbe essere più flessibile.
Se insisti per averlo in una procedura, puoi rendere facoltativi gli elementi della data e modificare il modello regex:
create or replace procedure show_missing_seqs(yy in varchar2 default '[0-9]{2}',
mm in varchar2 default '[0-9]{2}', dd in varchar2 default '[0-9]{2}') as
pattern varchar2(80);
cursor cur (pattern varchar2) is
with t as (
select to_number(substr(ename, 5, 4)) as seq,
substr(ename, 10, 2) as yy,
substr(ename, 13, 2) as mm,
substr(ename, 16, 2) as dd
from table1
where status = 2
and regexp_like(ename, pattern)
),
r (yy, mm, dd, seq, max_seq) as (
select yy, mm, dd, min(seq), max(seq)
from t
group by yy, mm, dd
union all
select yy, mm, dd, seq + 1, max_seq
from r
where seq + 1 <= max_seq
)
select yy, mm, dd, seq as missing_seq
from r
where not exists (
select 1 from t
where t.yy = r.yy
and t.mm = r.mm
and t.dd = r.dd
and t.seq = r.seq
)
order by yy, mm, dd, seq;
begin
pattern := 'emp[-][0-9]{4}[_]'
|| yy || '[_]' || mm || '[_]' || dd
|| '[_][0-9]{4}[_][G][1]';
for rec in cur(pattern) loop
dbms_output.put_line(to_char(rec.missing_seq, 'FM0000'));
end loop;
end show_missing_seqs;
/
Non so perché insisti che debba essere fatto in questo modo o perché vuoi usare dbms_output
poiché ti affidi al cliente/chiamante che lo visualizza; cosa farà il tuo lavoro con l'output? Potresti fare in modo che questo restituisca un sys_refcursor
che sarebbe più flessibile. ma comunque, puoi chiamarlo in questo modo da SQL*Plus/SQL Developer:
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114