2

データベースにアイテムを追加するとき、フィールド DisplayOrder の値を自動決定する必要があります。Identity (自動インクリメント) は理想的なソリューションですが、DisplayOrder 列の値をプログラムで変更 (UPDATE) できるようにする必要があり、Identity はそれを許可していないようです。とりあえず、次のコードを使用します。

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

それを行うのは良い方法ですか、それともより良い/簡単な方法はありますか?

4

5 に答える 5

1

ID プロパティを使用するように増分列を設定できます。次に、列に値を挿入する必要があるプロセスでSET IDENITY_INSERT、バッチでコマンドを使用できます。

ID プロパティを使用する挿入では、挿入ステートメントの列のリストから ID 列を除外します。

INSERT INTO [dbo].[MyTable] ( MyData ) VALUES ( @MyData )

ID 列の値を提供している行を挿入する場合は、次を使用します。

SET IDENTITY_INSERT MyTable ON

INSERT INTO [dbo].[MyTable] ( DisplayOrder, MyData )
VALUES ( @DisplayOrder, @MyData )

SET IDENTITY_INSERT MyTable OFF

他の手順を実行しなくても、列を UPDATE できるはずです。

コマンドを調べることもできますDBCC CHECKIDENT。このコマンドは、次の ID 値を設定します。次の ID 値が適切でない可能性がある行を挿入する場合は、コマンドを使用して新しい値を設定できます。

DECLARE @DisplayOrder INT

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

DBCC CHECKIDENT (MyTable, RESEED, @DisplayOrder)
于 2010-08-10T21:37:51.000 に答える
1

「Inside Microsoft SQL Server 2008: T-SQL Querying」からのこの問題の解決策

CREATE TABLE dbo.Sequence(
 val int IDENTITY (10000, 1) /*Seed this at whatever your current max value is*/
 )

GO

CREATE PROC dbo.GetSequence
@val AS int OUTPUT
AS
BEGIN TRAN
    SAVE TRAN S1
    INSERT INTO dbo.Sequence DEFAULT VALUES
    SET @val=SCOPE_IDENTITY()
    ROLLBACK TRAN S1 /*Rolls back just as far as the save point to prevent the 
                       sequence table filling up. The id allocated won't be reused*/
COMMIT TRAN

または、範囲をより簡単に割り当てる同じ本からの別の選択肢。(これをトランザクションの内部または外部から呼び出すかどうかを検討する必要があります。内部では、最初のトランザクションがコミットされるまで、他の同時トランザクションがブロックされます)

CREATE TABLE dbo.Sequence2(
 val int 
 )

GO

INSERT INTO dbo.Sequence2 VALUES(10000);

GO

CREATE PROC dbo.GetSequence2
@val AS int OUTPUT,
@n as int =1
AS
UPDATE dbo.Sequence2 
SET @val = val = val + @n;

SET @val = @val - @n + 1; 
于 2010-08-11T21:23:09.733 に答える
0

これが私が保持した解決策です:

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

BEGIN TRANSACTION

SET @DisplayOrder = (SELECT ISNULL(MAX(DisplayOrder), 0) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

COMMIT TRANSACTION
于 2010-08-11T21:01:29.650 に答える
-1

プロシージャをトランザクションとして実行するようにコマンドを追加する必要があります。そうしないと、2つの挿入を同時に実行すると、DisplayOrderに同じ値の2つの行が生成される可能性があります。

これは簡単に実現できます。追加

begin transaction

手順の開始時、および

commit transaction

最後に。

于 2010-08-10T21:08:06.647 に答える
-1

あなたはうまく機能し(少し変更して)、簡単です。@David Knellが言ったように、トランザクションでラップします。これにより、次のようなコードが生成されます。

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

BEGIN TRANSACTION

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

COMMIT TRANSACTION

SELECT と INSERT をトランザクションでラップすると、 DisplayOrderの値がAddItemによって複製されないことが保証されます。多数の同時追加 (毎秒多数) を行っている場合、MyTableで競合が発生する可能性がありますが、たまに挿入する場合は問題になりません。

于 2010-08-10T21:53:20.900 に答える