Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

menemukan nomor yang hilang dari urutan setelah mendapatkan urutan dari string?

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;

SQL Fiddle .

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 

SQL Fiddle .

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara mendapatkan nama elemen induk dalam ekspresi Oracle XPath?

  2. Cari database Oracle untuk tabel dengan nama kolom tertentu?

  3. Bagaimana cara membuat dan menggunakan daftar multi-pilih di APEX ORACLE?

  4. JPA dan 1000 ID digunakan di Oracle IN Operator

  5. bagaimana cara menjalankan fungsi dari TOAD untuk Oracle dan mengikat hasilnya ke kisi data?