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

Jak zaimplementować sekwencje wielowymiarowe

Jedynym sposobem, aby to zrobić, jest użycie tablicy kontrolnej kodu...

create table code_control
    (year number(4,0) not null
     , type varchar2(1) not null
     , last_number number(38,0) default 1 not null
     , primary key (year,type)
    )
organization index
/   

... który jest utrzymywany w ten sposób ...

create or replace function get_next_number
    (p_year in number, p_type in varchar2)
    return number
is
    pragma autonomous_transaction;
    cursor cur_cc is
        select last_number + 1
        from code_control cc
        where cc.year= p_year
        and cc.type = p_type
        for update of last_number;
    next_number number;
begin
    open cur_cc;
    fetch cur_cc into next_number;
    if cur_cc%found then
        update code_control
        set last_number = next_number
        where current of cur_cc;
    else
        insert into code_control (year,type)
        values (p_year, p_type)
        returning last_number into next_number;
    end if;    
    commit;
    return next_number;
end;
/

Ważną rzeczą jest WYBIERZ... DO AKTUALIZACJI. Pesymistyczne blokowanie gwarantuje wyjątkowość w środowisku wielu użytkowników. PRAGMA zapewnia utrzymanie code_control nie zanieczyszcza szerszej transakcji. Pozwala na wywołanie funkcji w wyzwalaczu bez zakleszczeń.

Oto tabela z kluczem takim jak twój:

create table t42
     (year number(4,0) not null
     , type varchar2(1) not null
     , id number(38,0) 
     , primary key (year,type, id)
)
/
create or replace trigger t42_trg
    before insert on t42 for each row
begin
    :new.id := get_next_number(:new.year, :new.type);
end;
/

Nie mam nic w rękawie, zanim wypełnię t42 :

SQL> select * from code_control;

no rows selected

SQL> select * from t42;

no rows selected

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'B');

1 row created.

SQL> insert into t42 (year, type) values (2016, 'A');

1 row created.

SQL> insert into t42 (year, type) values (2017, 'A');

1 row created.

SQL> select * from t42;

      YEAR T         ID
---------- - ----------
      2016 A          1
      2016 A          2
      2016 A          3
      2016 A          4
      2016 B          1
      2017 A          1

6 rows selected.

SQL> select * from code_control;

      YEAR T LAST_NUMBER
---------- - -----------
      2016 A           4
      2016 B           1
      2017 A           1

SQL> 

Oczywistym zarzutem wobec tej implementacji jest więc skalowalność. Transakcje wstawiane są serializowane na code_control stół. To absolutnie prawda. Jednak blokada jest utrzymywana przez najkrótszy możliwy czas, więc nie powinno to stanowić problemu, nawet jeśli t42 tabela jest wypełniana wiele razy na sekundę.

Jeśli jednak stół jest poddawany ogromnej liczbie równoczesnych wstawek, blokowanie może stać się problemem. Bardzo ważne jest, aby stół posiadał wystarczającą ilość slotów na Zainteresowane Transakcje (INITRANS, MAXTRANS), aby poradzić sobie z jednoczesnymi wymaganiami. Ale bardzo obciążone systemy mogą wymagać inteligentniejszej implementacji (być może generowania identyfikatorów w partiach); w przeciwnym razie zrezygnuj z klucza złożonego na rzecz sekwencji (ponieważ sekwencje skalują się w środowiskach wielu użytkowników).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-01008:nie wszystkie zmienne są powiązane, gdy wszystkie są powiązane

  2. Mały obiekt Blob lub Clob Oracle 10g nie jest przechowywany w trybie inline?

  3. Wyświetl wszystkie widoki bazy danych Oracle

  4. Wyrażenie regularne Oracle pasuje do białych znaków

  5. ORACLE SQL Group By STILL udziela duplikatów