Anda tidak ingin melihat dual
sama sekali di sini; tentu tidak mencoba untuk memasukkan. Anda perlu melacak nilai tertinggi dan terendah yang pernah Anda lihat saat Anda mengulangi melalui loop. berdasarkan beberapa elemen ename
mewakili tanggal Saya cukup yakin Anda ingin semua kecocokan Anda menjadi 0-9
, bukan 1-9
. Anda juga mengacu pada nama kursor saat Anda mengakses bidangnya, bukan nama variabel rekaman:
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;
Dengan nilai dalam tabel emp-1111_14_01_01_1111_G1
dan emp-1115_14_02_02_1111_G1
, yang melaporkan max_seq 1115 min_seq 1111
.
Jika Anda benar-benar ingin melibatkan dual, Anda dapat melakukannya di dalam loop, alih-alih pola if/then/assign, tetapi itu tidak perlu:
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Saya tidak tahu prosedur apa yang akan dilakukan; sepertinya tidak ada hubungan antara apa pun yang Anda dapatkan di test1
dan nilai yang Anda temukan.
Anda tidak memerlukan PL/SQL untuk ini. Anda bisa mendapatkan nilai min/maks dari kueri sederhana:
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
Dan Anda dapat menggunakannya untuk membuat daftar semua nilai dalam rentang tersebut:
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
Dan ekspresi tabel umum yang sedikit berbeda untuk melihat mana yang tidak ada di tabel Anda, yang menurut saya adalah yang Anda cari:
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
atau jika Anda lebih suka:
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Berdasarkan komentar, saya pikir Anda menginginkan nilai yang hilang untuk urutan untuk setiap kombinasi elemen ID lainnya (YY_MM_DD). Ini akan memberi Anda perincian itu:
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;
Dengan keluaran seperti:
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
Jika Anda ingin mencari tanggal tertentu, Anda menyaringnya (baik di t
, atau cabang pertama di r
), tetapi Anda juga dapat mengubah pola ekspresi reguler untuk menyertakan nilai tetap; jadi untuk mencari 14 06
polanya adalah 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, Misalnya. Itu lebih sulit untuk digeneralisasi, jadi filter (where t.yy = '14' and t.mm = '06'
mungkin lebih fleksibel.
Jika Anda bersikeras memiliki ini dalam suatu prosedur, Anda dapat membuat elemen tanggal opsional dan memodifikasi pola 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;
/
Saya tidak tahu mengapa Anda bersikeras itu harus dilakukan seperti ini atau mengapa Anda ingin menggunakan dbms_output
karena Anda mengandalkan klien/penelepon yang menampilkannya; apa yang akan pekerjaan Anda lakukan dengan output? Anda dapat mengembalikan ini sebagai sys_refcursor
yang akan lebih fleksibel. tapi bagaimanapun, Anda dapat menyebutnya seperti ini dari SQL*Plus/SQL Developer:
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114