Oracle
 sql >> Baza danych >  >> RDS >> Oracle

znajdowanie brakujących liczb z ciągu po pobraniu ciągu z ciągu?

Nie chcesz patrzeć na dual w ogóle tutaj; na pewno nie próbuję wstawiać. Musisz śledzić najwyższe i najniższe wartości, jakie widziałeś, przechodząc przez pętlę. na podstawie niektórych elementów ename reprezentujące daty Jestem prawie pewien, że chcesz, aby wszystkie dopasowania miały wartość 0-9 , a nie 1-9 . Odwołujesz się również do nazwy kursora, gdy uzyskujesz dostęp do jego pól, zamiast nazwy zmiennej rekordu:

  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;

Z wartościami w tabeli emp-1111_14_01_01_1111_G1 i emp-1115_14_02_02_1111_G1 , który zgłasza max_seq 1115 min_seq 1111 .

Jeśli naprawdę chciałbyś zaangażować podwójne, możesz to zrobić wewnątrz pętli, zamiast wzorca if/then/assign, ale nie jest to konieczne:

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

Nie mam pojęcia, co zrobi procedura; wydaje się, że nie ma związku między tym, co masz w test1 i wartości, które znajdujesz.

Nie potrzebujesz do tego żadnego PL/SQL. Możesz uzyskać wartości min./maks. z prostego zapytania:

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 

Możesz ich użyć do wygenerowania listy wszystkich wartości z tego zakresu:

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 

I nieco inne wspólne wyrażenie tabelowe, aby zobaczyć, które z nich nie istnieją w twoim stole, co moim zdaniem jest tym, czego szukasz:

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 

lub jeśli wolisz:

...
select v.seq as missing_seq
from v
where not exists (select 1 from t where t.seq = v.seq)
order by v.seq;

Skrzypce SQL .

Na podstawie komentarzy myślę, że chcesz brakować wartości dla sekwencji dla każdej kombinacji innych elementów identyfikatora (RR_MM_DD). To da ci ten podział:

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;

Z wyjściem takim jak:

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 

Skrzypce SQL .

Jeśli chcesz wyszukać konkretną datę, filtruj ją na zimno (albo w t lub pierwsza gałąź w r ), ale możesz również zmienić wzorzec wyrażenia regularnego, aby zawierał stałe wartości; więc poszukaj 14 06 wzorzec to 'emp[-][0-9]{4}_14_06_[0-9]{2}[_][0-9]{4}[_][G][1]' , na przykład. Trudniej to uogólnić, więc filtr (where t.yy = '14' and t.mm = '06' może być bardziej elastyczny.

Jeśli nalegasz, aby mieć to w procedurze, możesz uczynić elementy daty opcjonalnymi i zmodyfikować wzorzec wyrażenia regularnego:

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

Nie wiem, dlaczego upierasz się, że trzeba to zrobić w ten sposób ani dlaczego chcesz użyć dbms_output ponieważ polegasz na tym, że klient/rozmówca to wyświetla; co twoja praca zrobi z danymi wyjściowymi? Możesz sprawić, że to zwróci sys_refcursor który byłby bardziej elastyczny. ale w każdym razie możesz to nazwać tak od 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. Jaki jest najłatwiejszy sposób na zrobienie kolumny READONLY w Oracle?

  2. Jak uzyskać liczbę rekordów za pomocą kursora odniesienia w oracle10g?

  3. Tworzenie 32-bitowego obiektu ODP.Net OracleConnection jest bardzo powolne

  4. Porównanie daty Oracle zepsute z powodu czasu letniego

  5. Używanie `SELECT` do wywołania funkcji