Vous ne voulez pas regarder dual
du tout ici; certainement pas essayer d'insérer. Vous devez suivre les valeurs les plus élevées et les plus basses que vous avez vues pendant que vous parcourez la boucle. basé sur certains des éléments de ename
représentant des dates, je suis sûr que vous voulez que toutes vos correspondances soient 0-9
, pas 1-9
. Vous faites également référence au nom du curseur lorsque vous accédez à ses champs, au lieu du nom de la variable d'enregistrement :
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;
Avec des valeurs dans le tableau de emp-1111_14_01_01_1111_G1
et emp-1115_14_02_02_1111_G1
, qui rapporte max_seq 1115 min_seq 1111
.
Si vous vouliez vraiment impliquer dual, vous pourriez le faire à l'intérieur de la boucle, au lieu du modèle if/then/assign, mais ce n'est pas nécessaire :
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Je n'ai aucune idée de ce que la procédure va faire; il semble n'y avoir aucune relation entre ce que vous avez dans test1
et les valeurs que vous trouvez.
Vous n'avez cependant pas besoin de PL/SQL pour cela. Vous pouvez obtenir les valeurs min/max à partir d'une simple requête :
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
Et vous pouvez les utiliser pour générer une liste de toutes les valeurs de cette plage :
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
Et une expression de table commune légèrement différente pour voir laquelle de celles-ci n'existe pas dans votre table, ce qui, je pense, est ce que vous recherchez :
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
ou si vous préférez :
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Sur la base des commentaires, je pense que vous voulez les valeurs manquantes pour la séquence pour chaque combinaison des autres éléments de l'ID (YY_MM_DD). Cela vous donnera cette répartition :
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;
Avec une sortie comme :
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
Si vous souhaitez rechercher une date en particulier, vous filtrez celle-ci à froid (soit en t
, ou la première branche de r
), mais vous pouvez également modifier le modèle regex pour inclure les valeurs fixes ; donc chercher 14 06
le modèle serait 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, par exemple. C'est plus difficile à généraliser cependant, donc un filtre (where t.yy = '14' and t.mm = '06'
pourrait être plus flexible.
Si vous insistez pour l'avoir dans une procédure, vous pouvez rendre les éléments de date facultatifs et modifier le modèle de 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;
/
Je ne sais pas pourquoi vous insistez pour que cela soit fait comme ça ou pourquoi vous voulez utiliser dbms_output
car vous comptez sur le client/appelant affichant cela ; qu'est-ce que votre travail va faire avec la sortie ? Vous pouvez faire en sorte que ce retour soit un sys_refcursor
ce qui serait plus souple. mais quoi qu'il en soit, vous pouvez l'appeler ainsi depuis SQL*Plus/SQL Developer :
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114