Oracle
 sql >> база данни >  >> RDS >> Oracle

намиране на липсващи числа от последователност след получаване на последователност от низ?

Не искате да гледате dual изобщо тук; със сигурност не се опитва да вмъкне. Трябва да проследите най-високите и най-ниските стойности, които сте виждали, докато итерирате през цикъла. въз основа на някои от елементите на ename представляващи дати. Почти съм сигурен, че искате всичките ви съвпадения да са 0-9 , а не 1-9 . Вие също се позовавате на името на курсора, когато влизате в неговите полета, вместо на името на променливата за запис:

  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;

Със стойности в таблицата на emp-1111_14_01_01_1111_G1 и emp-1115_14_02_02_1111_G1 , който отчита max_seq 1115 min_seq 1111 .

Ако наистина искате да включите dual, можете да направите това вътре в цикъла, вместо шаблона if/then/assign, но не е необходимо:

      select least(min_seq, v_seq), greatest(max_seq, v_seq)
      into min_seq, max_seq
      from dual;

Нямам представа какво ще направи процедурата; изглежда няма връзка между всичко, което имате в test1 и стойностите, които намирате.

За това обаче нямате нужда от PL/SQL. Можете да получите минималните/максималните стойности от проста заявка:

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 

И можете да ги използвате, за да генерирате списък с всички стойности в този диапазон:

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 

И малко по-различен общ израз на таблица, за да видите кои от тях не съществуват във вашата таблица, което според мен е това, което търсите:

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 

или ако предпочитате:

...
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 .

Въз основа на коментарите мисля, че искате липсващите стойности за последователността за всяка комбинация от другите елементи на ID (YY_MM_DD). Това ще ви даде тази разбивка:

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;

С изход като:

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 .

Ако искате да търсите конкретна дата, филтрирайте студено това (или в t , или първия клон в r ), но можете също да промените модела на регулярен израз, за ​​да включите фиксираните стойности; така че да търсите 14 06 шаблонът ще бъде 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]' , например. Това обаче е по-трудно за обобщаване, така че филтър (where t.yy = '14' and t.mm = '06' може да е по-гъвкав.

Ако настоявате това да е в процедура, можете да направите елементите за дата незадължителни и да промените модела на регулярен израз:

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;
/

Не знам защо настоявате, че трябва да се направи по този начин или защо искате да използвате dbms_output тъй като разчитате на клиента/обаждащия се да покаже това; какво ще направи вашата работа с изхода? Можете да направите това връщане sys_refcursor което би било по-гъвкаво. но както и да е, можете да го извикате така от 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. Oracle SQL генерира случаен изход с listaggs

  2. Ant задача да провери дали база данни (връзка) съществува?

  3. В SQL, как мога да генерирам всяка възможна уникална комбинация от 5!56?

  4. BigQuery поддържа ли незабавно изпълнение на команда за изпълнение на динамична заявка?

  5. Прецизност на интервала за стойността на PL/SQL функция