8

次のように配置された複合主キーを持つテーブルがあります。

CREATE TABLE [dbo].[mytable]
(
    [some_id] [smallint] NOT NULL,
    [order_seq] [smallint] NOT NULL,
    -- etc...
)

これらの列はどちらも主キーの一部です (実際には、実際のテーブルでは 4 つの部分からなる PK ですが、例のために簡略化しています)。どの列も ID ではありません。order_seq指定された次のレコードに新しいレコードを挿入するストアド プロシージャを作成していsome_idます。

CREATE PROCEDURE some_proc
(
    @some_id smallint,
    @newSeq smallint OUTPUT
)
AS
BEGIN
    insert into mytable (some_id, order_seq)
    values 
    (
         @some_id, 
         (select max(order_seq) + 1 from mytable where some_id = @some_id)
    )

    set @newSeq = /* order_seq of the newly-inserted row */
END

@newSeq の設定方法を知る必要があります。同時実行の問題に遭遇したくないため、挿入後に選択クエリを実行することは避けたいと思います。テーブルをロックしたり、トランザクションを使用したりすることは禁止されています (質問しないでください)。

私の知る限りSCOPE_IDENTITY()、どの列もIDではないため使用できません。どうすればnewSeq正しく設定できますか?

4

4 に答える 4

5

まず、PKに4つの列が含まれている場合、各挿入には4つの列すべてが含まれている必要があります。次に、SQL Server 2005+を使用している場合は、Output句を調べることができます。

Declare @NewSeqTable Table( Order_Seq int not null )

Insert MyTable( some_id, order_seq, otherPkCol, otherPkCol2 )
Output inserted.order_seq Into @NewSeqTable
Select @some_id, Max( order_seq ) + 1, otherPkCol, otherPkCol2
From MyTable
Where some_id = @some_id

Select Order_Seq
From @NewSeqTable

OUTPUT句(Transact-SQL)

于 2011-04-28T22:02:33.270 に答える
2

ここでの答えは、システムのサイズ/同時実行の問題によって異なります。同時実行の問題について確信がない場合は、アクセスがマルチスレッドであると想定してください。

シングルスレッド

システムが小さい場合、または一度に1 つのスレッドのみがこの関数に触れることが確実な場合は、次のようなものが機能します。

CREATE PROCEDURE some_proc ( @KeyPart1 smallint, @newSeq smallint OUTPUT ) 
AS

DECLARE @KeyPart1 int
DECLARE @KeyPart2 int


SET @KeyPart1 = (SELECT <whatever your logic is here>)
SET @KeyPart2 =  select max(order_seq) + 1 from mytable where some_id = @KeyPart1

insert into mytable (some_id, order_seq)
values  ( @KeyPart1, @KeyPart2 )

set @newSeq = @KeyPart2

マルチスレッド アクセス

1 つのスレッドだけが proc にアクセスするという確信が持てない場合は、コードにトランザクションが必要です。あなたが共有した内容から、SERIALIZABLE取引が必要になるようです。 SERIALIZABLEは、SQL Server で使用できる同時実行が最も少ない (そして最も保護的な) トランザクションです。を識別する読み取りを行うmaxため、結果を変更するファントム挿入を防ぐためにシリアライズ可能にする必要があります。

エラー処理が必要になる可能性がありますが、次のような手順で機能するはずです....

CREATE PROCEDURE some_proc ( @KeyPart1 smallint, @newSeq smallint OUTPUT ) 
AS

DECLARE @KeyPart1 int
DECLARE @KeyPart2 int

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN

SET @KeyPart1 = (SELECT <whatever your logic is here>)
SET @KeyPart2 =  select max(order_seq) + 1 from mytable where some_id = @KeyPart1

insert into mytable (some_id, order_seq)
values  ( @KeyPart1, @KeyPart2 )

set @newSeq = @KeyPart2

COMMIT TRAN
于 2011-04-28T22:14:13.140 に答える
0

最初に@newSeqに割り当ててから、挿入で@newSeq変数を使用してみませんか?

于 2011-04-28T22:02:03.940 に答える