2011-01-31 16 views
6

SQL Serverのテーブルで、null以外のintとして定義されているserial_no列を処理しています。それは私の挿入ステートメントからその列を残しているかのように、自動的にインクリメントするフィールドではないようです。serial_noフィールドをnullにすることはできないというエラーが表示されます。SQLサーバー:次の使用可能なintを挿入します。

どのようにして次の番号を挿入しますか?

私はこの試みた:

INSERT INTO mytable (serial_no) VALUES ((SELECT MAX(serial_no)+1 FROM mytable)) 

を私はサブクエリはこの文脈で使用することができないというエラーを取得します。

EDIT:この表はオフ・シェルフ製品で使用されているので、デザインを変更してserial_no列を自動インクリメントにすることはできません。

+0

すべての行で一意でなければなりませんか?回答における推奨されるアプローチは、通常並行性安全ではありません。あなたは重複してしまうかもしれません.....あなたはどちらかをa)INT IDENTITY列にしてSQL Serverにそれを心配させる必要があります。b)obviuosよりもはるかに多くの作業を行います。SELECT MAX(serial_no)+ 1 "、またはc)SQL Server 2011を待って、それが' SEQUENCES'のコンセプトを使用する –

+0

marc_s、私は全く同意しますが、残念ながらDBデザインを変更することはできません。テーブルをロックして挿入してロックを解除するとどうなりますか?それが偽薬を作ることからそれを保護するだろうか?または待機中のクエリはロックが解放されるのを待ってから、とにかく#を挿入するでしょうか? –

+1

サードパーティ製アプリケーションがどのように値を作成し、同じように行うかを決定するためにトレースを実行できますか? ID列がない場合は、次の値を保持するためにテーブルを使用する可能性が高いと言います。この手法についてはすでに言及されている回答があります。 –

答えて

9

あなたはロックヒント

と書き込みの同時実行性を向上させることができますパフォーマンスが重要なis't場合は3210

、どちらかあなたが

DECLARE @retry bit 
SET @retry = 1 

WHILE @Retry = 1 
BEGIN 
    BEGIN TRY 
     INSERT INTO mytable (serial_no, value) 
     SELECT MAX (serial_no)+1, @value 
     FROM mytable WITH (ROWLOCK, XLOCK, HOLDLOCK) 

     SET @Retry = 0 
    END TRY 
    BEGIN CATCH 
     IF ERROR_NUMBER() <> 2627 --PK violation 
      RAISERROR ('blah', 16, 1) 
    END CATCH 
END 

を再試行するか、IDENTITY列に変更する必要があり、これは安全ではない与えられた、しかし、ROWLOCKの代わりに

XLOCK

をTABLOCKXを試してみてくださいそれを正しく実行してください...

+1

+1、最後の行は**太字**にする必要があります。可能であれば、 – cjk

+0

の識別情報が最良の選択です。ただし、手動で管理される固有のキーが必要な場合があります。これは私の今の場合に起こります。クライアントは、一意のFileNumberを要求します。これは、シーケンシャルで、ユーザーが編集可能で、毎年シーケンスの開始を変更します。 – George

+0

@George:SQL Server 2012のシーケンスは、 – gbn

2

エラーがVALUES

INSERT INTO mytable (serial_no, value) 

SELECT MAX(serial_no)+1 , 
@value 
FROM mytable) 

をドロップすることによって固定することができる。しかし、これは悪い考えです。 MAX(serial_no)+1に競合状態があります(例えば、2つのインサートがMax(Serial_no)に同じ値を取得します)

あなたは自動インクリメントフィールドを使う方が良いでしょう。次の値は、代わりに、最大を使用することをインクリメント

+1

+1このMAX()+ 1アプローチで重複の可能性を述べるため+1。オートインクリメントの解決策を提案する –

+0

問題は、それが自分のテーブルやアプリケーションではないということです。私はそれを変更することはできません。 –

0
INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable 
+1

安全でない - 2つのINSERTがほぼ同時に2つの接続から発生した場合、重複してしまう可能性があります。 –

0

VALUESせずにそれを試してみてください。

INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable 
+0

安全でない - 2つの接続から2つのINSERTがほぼ同時に発生した場合、重複する可能性があります。 .. –

+0

ええええ...ここでの醜い解決策は、トランザクションで挿入を実行することです... –

+2

醜いではない - 唯一の**実行可能で安全な**ソリューション! –

関連する問題