2017-04-07 6 views
-1

私はカラムの束を持つテーブルを持っています。その1つは[pos]という名前です。その列には数字が含まれています。新しいレコードを挿入するとき、私は新しいレコードを挿入することができますが、[pos]はデータベース内の最高の[pos]よりも1高い値に設定します。テーブルに挿入して、現在の最高番号に基づいてカラムをインクリメントする

Insert into table(c1,c2,pos) VALUES('c1','c2',?) 

私はあなただけMax(Pos)を引くと、それに1を追加することができますMSSQL

+0

これは**非常に**問題です。同じ時刻に行を追加しようとする2つのプロセス、max [pos]に同じ値を取得し、同じpos値を持つ2つの異なる行を追加しようとする2つのプロセスのリスクがあります。おそらくあなたの最善の賭けは私の答えのようなものですが、私はまだ解決策が気に入らないのです。 –

答えて

1

を使用しています:

Insert Table 
     (C1, C2, Pos) 
Select 'C1', 'C2', Max(Pos) + 1 
From Table 
+0

私はそのショットを与えるよ! – Damien

+1

この手法は[並行性の問題](http://stackoverflow.com/questions/8956044/avoiding-concurrency-problems-with-max1-integer-in-sql-server-2008-making-ow)に実行できますか? –

1

SQL Serverは、あなたのためにこれを管理することができます。 Posidentity columnとします。

-- Creating a identity column. 
DECLARE @Table TABLE 
(
    C1 VARCHAR(2), 
    C2 VARCHAR(2), 
    Pos INT IDENTITY (1, 1) 
); 

-- Populating the table. 
-- NOTE: SQL Server takes care of Pos for you. 
INSERT INTO @Table 
(
    C1, 
    C2 
) 
VALUES 
    ('C1', 'C2'), 
    ('C3', 'C4') 
; 

戻り

C1 C2 Pos 
C1 C2 1 
C3 C4 2 
+0

なぜ私はdownvotedされているのか分かりません。コメントを追加しないと、それは何でも修正することはできません。 –

+1

これは実際にこの問題を解決する最良の方法です。 downvoteは間違っています。 –

+0

私は@ GordonLinoffに同意します。潜在的な競合状態を引き起こさない唯一の他のオプションは、シーケンスを使用することです。 –

1

よく、単一の行のための直接的な方法:

insert into table(c1,c2,pos) 
select 'c1','c2',1+isnull((select max(pos) from table),0) 

は、値の複数のセットのためには、このような何かを行うことができます:

create table t (c1 char(2), c2 char(2), pos int); 

insert into t (c1,c2,pos) 
select v.c1,v.c2,row_number() over (order by (select 1))+x.MaxPos 
from (values ('c1','c2'),('d1','d2'),('e1','e2')) v (c1,c2) 
cross join (
    select MaxPos = isnull(max(pos),0) 
    from t 
) x; 

select * from t; 

rextesterデモ:http://rextester.com/DVJB25196

リターン:

+----+----+-----+ 
| c1 | c2 | pos | 
+----+----+-----+ 
| c1 | c2 | 1 | 
| d1 | d2 | 2 | 
| e1 | e2 | 3 | 
+----+----+-----+ 
0

これを行うには、いくつかの方法があります。しかし、私たちはあなたが提供しているより多くの情報を本当に必要としています。具体的には、(1)テーブルに[pos]と同じ値を持つ2つのエントリを持つことができますか?そして、(2)ユーザーは新しい[pos]値がテーブルの既存の値よりも低いことを指定できますか?この解決策の目的のために、私はこれらの質問の両方に対する答えが「いいえ」であると仮定します。

IDENTITYフィールドを使用するのが最も一般的ですが、仕様に基づいてIDENTITYのベースを複数回設定する必要がありますが、これは混乱して問題になる可能性があります。

シーケンスは、必要に応じてシーケンスのベースをリセットする必要があるため、同様の方法で使用できます。

テーブルの中で最大の値を見なければならない場合(特に、最も高い[pos]値を持つ行を削除できる場合は特に重要です)、[pos]列にUNIQUE制約を設定する必要がありますすべての挿入または削除にトランザクションを使用し、最大値を取得または削除するときはTABLOCKヒントおよびROWLOCKヒントを使用します。トランザクションを開始し、ROWLOCKヒントまたはTABLOCKヒントを使用してSQL内で最高の[pos]値を読み込み、ただちに新しい行を追加し、トランザクションをコミットし、ロックが解除されていることを確認することが唯一の方法です何を求めているようだ。

関連する問題