Je wilt niet kijken naar dual
helemaal hier; zeker niet proberen in te voegen. U moet de hoogste en laagste waarden bijhouden die u hebt gezien terwijl u door de lus loopt. gebaseerd op enkele elementen van ename
datums vertegenwoordigen Ik ben er vrij zeker van dat je wilt dat al je matches 0-9
zijn , niet 1-9
. Je verwijst ook naar de naam van de cursor als je de velden opent, in plaats van de naam van de recordvariabele:
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;
Met waarden in de tabel van emp-1111_14_01_01_1111_G1
en emp-1115_14_02_02_1111_G1
, dat meldt max_seq 1115 min_seq 1111
.
Als je echt dual wilt gebruiken, kun je dit binnen de lus doen, in plaats van het if/then/assign-patroon, maar het is niet nodig:
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Ik heb geen idee wat de procedure gaat doen; er lijkt geen verband te zijn tussen wat je ook hebt in test1
en de waarden die u vindt.
Je hebt hier echter geen PL/SQL voor nodig. U kunt de min/max-waarden uit een eenvoudige query halen:
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
En u kunt die gebruiken om een lijst met alle waarden in dat bereik te genereren:
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
En een iets andere algemene tabeluitdrukking om te zien welke niet in uw tabel voorkomen, waarvan ik denk dat dit is wat u zoekt:
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
of als je wilt:
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Op basis van opmerkingen denk ik dat je de ontbrekende waarden voor de reeks wilt voor elke combinatie van de andere elementen van de ID (YY_MM_DD). Dit geeft je die uitsplitsing:
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;
Met uitvoer zoals:
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
Als je naar een bepaalde datum wilt zoeken, filter je die koud (ofwel in t
, of de eerste vertakking in r
), maar u kunt ook het regex-patroon wijzigen om de vaste waarden op te nemen; dus zoek naar 14 06
het patroon zou zijn 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, bijvoorbeeld. Dat is echter moeilijker te generaliseren, dus een filter (where t.yy = '14' and t.mm = '06'
misschien flexibeler.
Als u erop staat dit in een procedure te hebben, kunt u de datumelementen optioneel maken en het regexpatroon wijzigen:
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;
/
Ik weet niet waarom je erop staat dat het zo moet of waarom je dbms_output
wilt gebruiken omdat u erop vertrouwt dat de klant/beller dat weergeeft; wat doet uw werk met de output? Je zou van deze return een sys_refcursor
kunnen maken wat flexibeler zou zijn. maar hoe dan ook, je kunt het zo noemen vanuit SQL*Plus/SQL Developer:
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114