すべての親アイテムが挿入された後にカスタムシーケンスを挿入するトリガーがあります。これで、親アイテムIDを介して親アイテムにリンクされたサブアイテムがあり(シーケンスと親アイテムIDは2つの異なる列です)、サブアイテムは1を超える場合があります。親アイテムのトリガーによってシーケンスが「P2505」として生成され、サブアイテムシーケンスは「P2505-1」、2番目のサブアイテムは「P2505-2」のようにする必要があります。
次の親アイテムのシーケンスが「P2506」の場合、サブアイテムシーケンスは「P2506-1」のようになります。
これは、親アイテムのシーケンスを生成するためのトリガーです
create or replace trigger REF_NO_TRIGGER
before insert on LOST_ITEM
for each row
declare
PREFIX varchar2(254);
begin
select NAME into PREFIX
from SUBCAT
where SUBCAT.ID = :new.SUBCAT_ID;
:new.SEQUENCE := substr(PREFIX,1,1)
||(:new.CATEGORY_ID)
||(:new.SUBCAT_ID)
||(:new.ID);
end;
ID NUMBER(15,0)
CATEGORY_ID NUMBER(3,0)
SUBCAT_ID NUMBER(5,0)
NAME VARCHAR2(20)
SEQUENCE VARCHAR2(22 BYTE)
ID NUMBER(30,0)
PARENT_ITEM_ID NUMBER(15,0)
NAME VARCHAR2(20)
SEQUENCE VARCHAR2(22 BYTE)
CREATE TABLE PARENT_ITEM(ID NUMBER(15) GENERATED BY DEFAULT AS IDENTITY (START WITH 1 INCREMENT BY 1),
CATEGORY_ID NUMBER(3) NOT NULL,
SUBCAT_ID NUMBER(5) NOT NULL,
NAME VARCHAR2(20) NOT NULL,
SEQUENCE VARCHAR2(22),
PRIMARY KEY (ID)
);
CREATE TABLE SUB_ITEM(ID NUMBER(30) GENERATED BY DEFAULT AS IDENTITY (START WITH 1 INCREMENT BY 1),
PARENT_ITEM_ID NUMBER(15) NOT NULL,
NAME VARCHAR2(20),
SEQUENCE VARCHAR2(22 BYTE),
CONSTRAINT FK_LOST_IT_SUB_LOST_IT FOREIGN KEY (PARENT_ITEM_ID) REFERENCES PARENT_ITEM(ID),
PRIMARY KEY (ID)
);
INSERT INTO PARENT_ITEM(CATEGORY_ID, SUBCAT_ID, NAME) VALUES (2,5,'MAIN_ITEM');
ID IS GENERATEDが自動的に生成され、トリガーによって親アイテムのシーケンスが生成されます。サブアイテムの場合、名前と親アイテムIDのみを挿入するので、そのためのシーケンスが必要です。
私の理解に従って、サブアイテムテーブルで親アイテムシーケンスを確認し、エントリがあるかどうかを確認する必要があります。そのシーケンスにエントリがない場合、最初のサブアイテムは「ParentItemSequence-1」である必要があります。 「-2」、「-3」などを数えて追加
しかし、親とサブアイテムを含むすべてのアイテムを同時に送信する必要があるため、トリガーを介してこの機能を実現する方法がわかりません。
探しているものは、「ギャップのない連続番号」と呼ばれます。
これらのタイプのビジネスリクエストは、関連するテーブルのパフォーマンスを低下させることが知られています。これは、番号を生成するエンティティで必要なシリアル化が原因です。
PARENT_ITEM.ID
は「ギャップのない連番」にはなりません。 NOCACHE
オプションがありません。
それでも、まだギャップがある可能性があります。
CHILD_ITEM.ID
を代理キーとして保持することをお勧めします。 Identity列はデフォルトのままにします。また、「-1」を表す数値の別の列が必要です。この列をCHILD_NUMBER_SEQUENCE
と呼びます。
ここで、CHILD_SEQUENCE
の「ナンバジェネレータ」をシリアル化するには、PARENT_ITEM_ID
に基づくロックを取得する必要があります。
Oracleの場合、最も簡単な方法は親行をロックすることです。テーブルPARENT_ITEM
が「現在の子シーケンス番号」を保持している場合、「親行をロックする」と同時に「次の値を取得する」ことができるため、アルゴリズムは簡単になります。
テーブルの変更
alter table parent_item add ( current_child_sequence_number number(5) default 0);
alter table child_item add (child_sequence_number number(5) not null);
alter table child_item add
constraint child_item_uq1 unique (parent_item_id, child_sequence_number);
「CHILD_ITEM.CHILD_SEQUENCE_NUMBER」を生成するコード
-- this locks and updates the parent row.
update parent_item p
set p.current_child_sequence_number = nvl(p.current_child_sequence_number,0) + 1
where p.id = :new.parent_item_id
returning p.current_child_sequence_number into :new.child_sequence_number;
-- make sure you check that 1 and only 1 row was updated.
-- fail if that isn't true.
コードは、単一行の処理に固有です。
一括読み込みのパフォーマンスが必要な場合は、ステージングテーブル(グローバル一時テーブルなど)とプロシージャを使用する必要があります。
繰り返しになりますが、「ギャップのない連番」のビジネス要件は本質的に遅いです。それが高速であると期待しないでください。