誰かが同様の質問を投稿して以来、私はこれについて熟考してきました。最初の問題は、DBが「パーティション化可能な」シーケンスを提供しないことです(異なるキーに基づいて再起動/記憶します)。 2つ目は、SEQUENCE
であるオブジェクト 提供されるのは高速アクセスを対象としており、ロールバックすることはできません(つまり、 ギャップを取得します)。これは本質的に、組み込みのユーティリティを使用することを除外します...つまり、独自のユーティリティをロールする必要があります。
最初に必要になるのは、シーケンス番号を格納するためのテーブルです。これはかなり簡単です:
CREATE TABLE Invoice_Sequence (base CHAR(1) PRIMARY KEY CLUSTERED,
invoiceNumber INTEGER);
実際には、base
列は、請求書を発行するビジネス/エンティティを定義するテーブル/IDへの外部キー参照である必要があります。このテーブルでは、エントリを発行済みエンティティごとに一意にする必要があります。
次に、キー(base
)を受け取るストアドプロシージャが必要です。 )そしてシーケンスの次の番号を吐き出します(invoiceNumber
)。必要なキーのセットはさまざまです(つまり、一部の請求書番号には発行年または完全な発行日が含まれている必要があります)が、この状況の基本フォームは次のとおりです。
CREATE PROCEDURE Next_Invoice_Number @baseKey CHAR(1),
@invoiceNumber INTEGER OUTPUT
AS MERGE INTO Invoice_Sequence Stored
USING (VALUES (@baseKey)) Incoming(base)
ON Incoming.base = Stored.base
WHEN MATCHED THEN UPDATE SET Stored.invoiceNumber = Stored.invoiceNumber + 1
WHEN NOT MATCHED BY TARGET THEN INSERT (base) VALUES(@baseKey)
OUTPUT INSERTED.invoiceNumber ;;
注:
- あなたはしなければならない これをシリアル化されたトランザクションで実行します
- トランザクションは必須 宛先(請求書)テーブルに挿入するものと同じである必要があります。
そうです、請求書番号を発行するときに、ビジネスごとにブロックすることができます。 できません 請求書番号が連続していてギャップがない必要がある場合は、これを避けてください。行が実際にコミットされるまで、ロールバックされる可能性があります。つまり、請求書番号は発行されません。
ここで、エントリのプロシージャを呼び出すことを忘れないようにする必要があるため、トリガーでラップします。
CREATE TRIGGER Populate_Invoice_Number ON Invoice INSTEAD OF INSERT
AS
DECLARE @invoiceNumber INTEGER
BEGIN
EXEC Next_Invoice_Number Inserted.base, @invoiceNumber OUTPUT
INSERT INTO Invoice (base, invoiceNumber)
VALUES (Inserted.base, @invoiceNumber)
END
(明らかに、自動入力する必要がある他の列を含め、より多くの列があります。それらに入力する必要があります)
...次に、次のように言うだけで使用できます:
INSERT INTO Invoice (base) VALUES('A');
では、私たちは何をしましたか?ほとんどの場合、この作業はすべて、トランザクションによってロックされる行の数を減らすことに関するものでした。このINSERT
まで がコミットされている場合、ロックされている行は2つだけです:
-
Invoice_Sequence
の行 シーケンス番号の維持 Invoice
の行 新しい請求書の場合。
特定のbase
の他のすべての行 無料です-自由に更新または照会できます(この種のシステムから情報を削除すると、会計士は神経質になる傾向があります)。クエリに通常、保留中の請求書が含まれる場合にどうなるかを決定する必要があります...