Bạn không muốn nhìn vào dual
ở tất cả ở đây; chắc chắn không cố gắng chèn. Bạn cần theo dõi các giá trị cao nhất và thấp nhất mà bạn đã thấy khi lặp qua vòng lặp. dựa trên một số phần tử của ename
thể hiện ngày tháng Tôi khá chắc rằng bạn muốn tất cả các kết quả phù hợp của mình là 0-9
, không phải 1-9
. Bạn cũng đang đề cập đến tên con trỏ khi bạn truy cập vào các trường của nó, thay vì tên biến bản ghi:
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;
Với các giá trị trong bảng của emp-1111_14_01_01_1111_G1
và emp-1115_14_02_02_1111_G1
, báo cáo max_seq 1115 min_seq 1111
.
Nếu bạn thực sự muốn liên quan đến kép, bạn có thể thực hiện điều này bên trong vòng lặp, thay vì mẫu if / then / gán, nhưng nó không cần thiết:
select least(min_seq, v_seq), greatest(max_seq, v_seq)
into min_seq, max_seq
from dual;
Tôi không biết thủ tục sẽ làm gì; dường như không có mối quan hệ nào giữa những gì bạn có trong test1
và các giá trị bạn đang tìm kiếm.
Bạn không cần bất kỳ PL / SQL nào cho việc này. Bạn có thể nhận các giá trị tối thiểu / tối đa từ một truy vấn đơn giản:
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
Và bạn có thể sử dụng những giá trị đó để tạo danh sách tất cả các giá trị trong phạm vi đó:
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
Và một biểu thức bảng thông thường hơi khác để xem biểu thức nào trong số đó không tồn tại trong bảng của bạn, mà tôi nghĩ đó là những gì bạn đang theo đuổi:
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
hoặc nếu bạn thích:
...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;
Dựa trên các nhận xét, tôi nghĩ bạn muốn các giá trị còn thiếu cho chuỗi cho mỗi kết hợp của các phần tử khác của ID (YY_MM_DD). Điều này sẽ cung cấp cho bạn bảng phân tích đó:
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;
Với đầu ra như:
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
Nếu bạn muốn tìm một ngày cụ thể, bạn lọc lạnh (trong t
hoặc nhánh đầu tiên trong r
), nhưng bạn cũng có thể thay đổi mẫu regex để bao gồm các giá trị cố định; vì vậy để tìm 14 06
mẫu sẽ là 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]'
, Ví dụ. Tuy nhiên, điều đó khó tổng quát hơn, vì vậy một bộ lọc (where t.yy = '14' and t.mm = '06'
có thể linh hoạt hơn.
Nếu bạn khăng khăng muốn có điều này trong một thủ tục, bạn có thể làm cho các phần tử ngày tháng tùy chọn và sửa đổi mẫu 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;
/
Tôi không biết tại sao bạn nhấn mạnh rằng nó phải được thực hiện như thế này hoặc tại sao bạn muốn sử dụng dbms_output
khi bạn đang dựa vào máy khách / người gọi hiển thị điều đó; công việc của bạn sẽ làm gì với đầu ra? Bạn có thể đặt trả về này là sys_refcursor
sẽ linh hoạt hơn. nhưng dù sao, bạn có thể gọi nó như thế này từ SQL * Plus / SQL Developer:
set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');
anonymous block completed
1112
1113
1114