2012-12-21 15 views
9

一意の非自動インクリメントプライマリキーを持つテーブルに行を挿入したいとします。SQL Serverテーブルにauto_incrementキーを挿入する方法

は、ネイティブSQL関数は、最後のキーを評価し、それをインクリメントするありますか私は2つのステップでそれをしなければならないん

key = select max(primary.key) + 1 

INSERT INTO dbo.TABLE (primary.key, field1, fiels2) VALUES (KEY, value1, value2) 
+3

テーブルに[IDENTITY列](http://msdn.microsoft.com/en-us/library/ms186775.aspx)がありますか?もしそうなら、どのような正確な問題があるのでしょうか?それについては、このサイトのドキュメンテーションや[多くの質問](http://stackoverflow.com/search?q=sql+identity)で議論されていませんか?下のコメントでは、エラーについて言及していますが、それが何であるかは正確には述べていません。理想的には、あなたの 'CREATE TABLE'スクリプト、あなたの' INSERT'ステートメント、そしてその結果のエラーメッセージを表示してください。 – Pondlife

+0

このスレッドは私のすべての頭痛を解決し、コードはコンパイルされています。なぜpplがこれを落としたのですか? –

答えて

10

全体を通してコメントをしていると、ID列ではない表に主キーがあります。

SQL ServerのバージョンがSQL 2012である場合は、シーケンスになります。あなたはIDENTITYプロパティを使用してテーブルを再作成する必要がありますいずれかの他のバージョンではhttp://msdn.microsoft.com/en-us/library/ff878091.aspx

(http://msdn.microsoft.com/en -us/library/aa933196(v = sql.80).aspx)を使用するか、2段階アプローチを使用します。

2ステップアプローチを使用する場合は、同時に実行している挿入が同じ新しい値を使用しないようにする必要があります。最良の答えはPK列があるように、あなたのテーブルを修正することです私の意見では

CREATE TABLE dbo.Tbl1(id INT PRIMARY KEY, val1 INT, val2 INT) 

INSERT INTO dbo.Tbl1(id, val1, val2) 
VALUES((SELECT ISNULL(MAX(id)+1,0) FROM dbo.Tbl1 WITH(SERIALIZABLE, UPDLOCK)), 42, 47); 

SELECT * FROM dbo.Tbl1; 
+0

ありがとうございます!今は解決策がありますが、それは機能ではありませんが、私はサブクエリーで管理することができます.2段階の手順より優れています。ありがとう。 –

+0

'SERIALIZABLE'は' HOLDLOCK'に相当し、良いスタートですが*十分ではありません*。高い並列度でクエリが失敗する可能性があります。 'UPDLOCK、TABLOCKX'を追加する必要があります。クエリの部分は時間と共に実行され、時間の経過とともにロックが取得されるので、 'INSERT'は' SELECT'の後に来ます。 2つのクライアントは、完全に互換性のある読取りロックで同時に「SELECT」することができ、第2のブロックはブロックされ、第1のブロックは「INSERT」のために「UPDLOCK」に変換され、第2のブロックは以上。 **すべての読者**をブロックするには 'SELECT'が必要です! – ErikE

+1

最終的に、この 'SELECT max()+ 1'パターンはベストプラクティスではなく、推奨できません。アイデンティティ列は正確にこの理由から存在します。それらを使用してください。 – ErikE

17

それが自動生成されますので、単純にそれを提供していません。

INSERT INTO bo.TABLE (field1, fiels2) VALUES (value1, value2) 

更新:あなたの列がIDENTITY列であれば動作します。

set identity_insert bo.TABLE on 

INSERT INTO bo.TABLE (primary_key, field1, fiels2) VALUES ((SELECT ISNULL(MAX(id) + 1, 0) FROM bo.Table), value1, value2) 

set identity_insert bo.TABLE off 

をしかし、それをこのように行うための説得力のある理由はありません。

は、ID列に明示的な値を提供するには、これをしなければなりません。

+0

私はそれを試して、制約エラーをスローし、私は値を提供する必要があります。 –

+1

エラー....とあなたのテーブル定義を投稿してください。 –

+0

PRIMARY KEY制約 'pk_bo'に違反しています。オブジェクト 'dbo.bo'に重複キーを挿入できません。重複するキー値は(921、0、2012)です。 –

3

:それを行う最も簡単な方法は、これは一つの値に選択し、挿入を組み合わせると、シリアライズテーブルヒントを使用することですですID列。 (現在選択されている答えがなぜ最善でないのかについては、Sebastian Meineの答えに対する私のコメントを見てください。)既存のPKをID列にする唯一の方法は、テーブルを交換することです。大まかに:

BEGIN TRAN; 
-- Rename all constraints in original table 
EXEC sp_rename 'dbo.YourOriginalTable.PK_ConstraintName', 'PKConstraint_Backup'; 
EXEC sp_rename 'dbo.YourOriginalTable.OtherConstraintName', 'OtherConstraintName_Backup'; 
CREATE TABLE dbo.WorkTable (
    YourPKColumn int identity(1, 1) NOT NULL -- your PK converted to identity 
    CONSTRAINT PK_YourOriginalTableConstraintName PRIMARY KEY CLUSTERED, 
    AllOtherColumns -- all your other columns exactly as in the original table 
); 

SET IDENTITY_INSERT dbo.WorkTable ON; 
INSERT dbo.WorkTable (YourPKColumn, AllOtherColumns) 
SELECT YourPKColumn, AllOtherColumns 
FROM dbo.YourOriginalTable WITH (TABLOCKX, HOLDLOCK); 

SET IDENTITY_INSERT dbo.WorkTable OFF; 

-- Drop all FK constraints from other tables pointing to your table 
ALTER TABLE dbo.TableWithFK_1 
DROP CONSTRAINT FK_TableWithFK_1_YourOriginalTableSomethingID; 

-- Swap out the tables 
EXEC sp_rename 'dbo.YourOriginalTable', 'YourOriginalTableBackup'; 
EXEC sp_rename 'dbo.WorkTable', 'YourOriginalTable'; 

-- If you didn't add them in the WorkTable creation, 
-- add all other removed or needed constraints creation 
ALTER TABLE dbo.YourOriginalTable 
ADD CONSTRAINT OriginalConstraint (OriginalConstraintColumns); 
-- Add back FK constraints from other tables to this one. 
COMMIT TRAN; 

これで、クラスタ化されたPKを持つID列を持つテーブルが作成されました。それに問題はありません。もはや同時実行性の問題と愚かなSELECT Max() + 1ジャンクですので、間違って簡単に

+0

もちろん、これがアクティブなシステムの場合は、明示的なトランザクションでこれを実行する必要があります。それ以外の場合は、 'INSERT'の後で名前の前に' YourOriginalTable'にデータが入る危険性があります。 –

+0

Aaronさん、ありがとうございます。修正済み(私は思う)。 – ErikE

+0

申し訳ありません私のDbではない、私は何も変更することはできません、それはERPアプリケーションで動作するように設計されました。ちょうど質問で説明された手順を行う必要がある、とにかくありがとう。 –

0

のEmp ( EIDはint(10)NOT NULL主キーAUTO_INCREMENT、 名前はvarchar(45)nullではない、 年齢はint(5)デフォルト20、 給与INT(5) )が存在しない場合は、テーブルを作成します emp値に挿入する(102、 'Ranjan'、21,450000);

次に、以下のSQLクエリを試してください。それは自動的にeidを次の番号にインクリメントします。

emp(名前、給与)の値( 'Lisma'、118500)に挿入します。

select * from emp;

関連する問題