Nechcete se dívat na dual
vůbec tady; určitě se nepokouší vložit. Při iteraci smyčkou musíte sledovat nejvyšší a nejnižší hodnoty, které jste viděli. na základě některých prvků ename
představující data Jsem si docela jistý, že chcete, aby všechny vaše shody byly 0-9
, nikoli 1-9
. Při přístupu k jeho polím také odkazujete na název kurzoru namísto názvu proměnné záznamu:
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;
S hodnotami v tabulce emp-1111_14_01_01_1111_G1
a emp-1115_14_02_02_1111_G1
, který uvádí max_seq 1115 min_seq 1111
.
Pokud jste opravdu chtěli zapojit dual, můžete to udělat uvnitř smyčky místo vzoru if/then/assign, ale není to nutné:
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Nemám ponětí, co ten postup udělá; zdá se, že mezi tím, co máte v test1
, není žádný vztah a hodnoty, které nacházíte.
K tomu však nepotřebujete žádné PL/SQL. Hodnoty min/max můžete získat z jednoduchého dotazu:
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
A můžete je použít ke generování seznamu všech hodnot v tomto rozsahu:
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
A trochu jiný běžný tabulkový výraz, abyste viděli, které z nich ve vaší tabulce neexistují, což je podle mě to, co hledáte:
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
nebo chcete-li:
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Na základě komentářů si myslím, že chcete chybějící hodnoty pro sekvenci pro každou kombinaci ostatních prvků ID (YY_MM_DD). Toto vám poskytne rozpis:
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;
S výstupem jako:
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
Pokud chcete vyhledat konkrétní datum, vyfiltrujte to (buď v t
, nebo první větev v r
), ale můžete také změnit vzor regulárního výrazu tak, aby zahrnoval pevné hodnoty; takže hledejte 14 06
vzor by byl 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, například. To je však těžší zobecnit, takže filtr (where t.yy = '14' and t.mm = '06'
může být flexibilnější.
Pokud trváte na tom, aby to bylo v proceduře, můžete nastavit prvky data jako nepovinné a upravit vzor regulárního výrazu:
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;
/
Nevím, proč trváte na tom, že se to musí udělat takto, nebo proč chcete použít dbms_output
protože se spoléháte na to, že to klient/volající zobrazí; co udělá vaše práce s výstupem? Můžete to udělat tak, aby vrátilo sys_refcursor
která by byla flexibilnější. ale každopádně to můžete nazvat takto z SQL*Plus/SQL Developer:
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114