sql >> Databáze >  >> RDS >> Oracle

najít chybějící čísla ze sekvence po získání sekvence z řetězce?

Nechcete se dívat na dual vůbec tady; určitě se nepokouší vložit. Při iteraci smyčkou musíte sledovat nejvyšší a nejnižší hodnoty, které jste viděli. na základě některých prvků ename představující data Jsem si docela jistý, že chcete, aby všechny vaše shody byly 0-9 , nikoli 1-9 . Při přístupu k jeho polím také odkazujete na název kurzoru namísto názvu proměnné záznamu:

  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;

S hodnotami v tabulce emp-1111_14_01_01_1111_G1 a emp-1115_14_02_02_1111_G1 , který uvádí max_seq 1115 min_seq 1111 .

Pokud jste opravdu chtěli zapojit dual, můžete to udělat uvnitř smyčky místo vzoru if/then/assign, ale není to nutné:

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

Nemám ponětí, co ten postup udělá; zdá se, že mezi tím, co máte v test1, není žádný vztah a hodnoty, které nacházíte.

K tomu však nepotřebujete žádné PL/SQL. Hodnoty min/max můžete získat z jednoduchého dotazu:

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 

A můžete je použít ke generování seznamu všech hodnot v tomto rozsahu:

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 

A trochu jiný běžný tabulkový výraz, abyste viděli, které z nich ve vaší tabulce neexistují, což je podle mě to, co hledáte:

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 

nebo chcete-li:

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

Na základě komentářů si myslím, že chcete chybějící hodnoty pro sekvenci pro každou kombinaci ostatních prvků ID (YY_MM_DD). Toto vám poskytne rozpis:

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;

S výstupem jako:

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 .

Pokud chcete vyhledat konkrétní datum, vyfiltrujte to (buď v t , nebo první větev v r ), ale můžete také změnit vzor regulárního výrazu tak, aby zahrnoval pevné hodnoty; takže hledejte 14 06 vzor by byl 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]' , například. To je však těžší zobecnit, takže filtr (where t.yy = '14' and t.mm = '06' může být flexibilnější.

Pokud trváte na tom, aby to bylo v proceduře, můžete nastavit prvky data jako nepovinné a upravit vzor regulárního výrazu:

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

Nevím, proč trváte na tom, že se to musí udělat takto, nebo proč chcete použít dbms_output protože se spoléháte na to, že to klient/volající zobrazí; co udělá vaše práce s výstupem? Můžete to udělat tak, aby vrátilo sys_refcursor která by byla flexibilnější. ale každopádně to můžete nazvat takto z SQL*Plus/SQL Developer:

set serveroutput on
exec show_missing_seqs(yy => '14', mm => '01');

anonymous block completed
1112
1113
1114



  1. Nesprávná syntaxe poblíž ')' volání uložené procedury s GETDATE

  2. SQL Server Database Change Listener C#

  3. Vazba int64 (SQL_BIGINT) jako parametr dotazu způsobuje chybu během provádění v Oracle 10g ODBC

  4. Jak mohu vybrat nejnovější záznam v mysql?