これを行う唯一の方法は、コード制御テーブルを使用することです...
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
/
...このように維持されます...
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;
/
重要なのはSELECT...FORUPDATEです。ペシミスティックロックは、マルチユーザー環境での一意性を保証します。 PRAGMAは、code_control
を維持することを保証します より広範なトランザクションを汚染しません。これにより、デッドロックなしでトリガーで関数を呼び出すことができます。
これがあなたのようなキーの表です:
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;
/
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>
したがって、この実装に対する明らかな反対意見はスケーラビリティです。挿入トランザクションは、code_control
でシリアル化されます テーブル。それは絶対に真実です。ただし、ロックは可能な限り短い時間保持されるため、t42
であっても、これは問題にはなりません。 テーブルは1秒間に何度も入力されます。
ただし、テーブルが大量の同時挿入にさらされると、ロックが問題になる可能性があります。同時要求に対処するために、テーブルに十分な関心のあるトランザクションスロット(INITRANS、MAXTRANS)があることが重要です。ただし、非常にビジーなシステムでは、よりスマートな実装が必要になる場合があります(IDをバッチで生成する可能性があります)。それ以外の場合は、シーケンスを優先して複合キーを破棄します(シーケンスはマルチユーザー環境でスケーリングするため)。