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

Jak implementovat vícerozměrné sekvence

Jediný způsob, jak toho dosáhnout, je pomocí řídicí tabulky kódu ...

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
/   

... který je udržován takto ...

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

Důležité je VYBRAT ... PRO AKTUALIZACI. Pesimistické zamykání zaručuje jedinečnost ve víceuživatelském prostředí. PRAGMA zajišťuje zachování code_control neznečišťuje širší transakci. Umožňuje nám volat funkci ve spoušti bez uváznutí.

Zde je tabulka s klíčem, jako je ten váš:

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

Než naplním t42, nemám nic v rukávu :

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> 

Zjevnou námitkou proti této implementaci je tedy škálovatelnost. Vkládání transakcí je serializováno na code_control stůl. To je naprostá pravda. Zámek je však držen na nejkratší možnou dobu, takže by to neměl být problém, i když t42 tabulka je obsazena mnohokrát za sekundu.

Pokud je však stůl vystaven velkému počtu souběžných vložek, může se zamykání stát problémem. Je velmi důležité, aby stůl měl dostatek slotů pro zainteresované transakce (INITRANS, MAXTRANS), aby zvládl souběžné požadavky. Ale velmi vytížené systémy mohou potřebovat chytřejší implementaci (možná generování ID v dávkách); jinak opustit složený klíč ve prospěch sekvence (protože sekvence se škálují v prostředí s více uživateli).




  1. MySQL:jak odstranit dvojité nebo více mezer z řetězce?

  2. Příklady SQUARE() v SQL Server

  3. Jak SUBTIME() funguje v MariaDB

  4. Získání oracle.jdbc.driver.LogicalConnection, potřebujete oracle.jdbc.OracleConnection