47


16

Microsoft SQL Server 2005で次のことをどのように言いますか。

存在する場合(SELECT * FROMテーブルのWHERE FieldValue = '')テーブルからのSELECTテーブルIDの値WHERE FieldValue = ''テーブルへの新規挿入(FieldValue)値テーブルの先頭からのテーブルIDの選択WHERE TableID = SCOPE_IDENTITY()

私がやろうとしているのは、すでに空のフィールド値があるかどうかを確認することです。そして、そのTableIDが返される場合は、空のフィールド値を挿入して対応する主キーを返します。

7 回答


59


2つの同時クライアントが同じfieldValueを2回挿入しないようにするには、トランザクションでこれを実行する必要があります。

トランザクションの分離レベルの直列化を開始することができます。開始のトランザクションを宣言します。 @idコミットトランザクション

ロックのオーバーヘッドを減らすために Double-checked lockingを使うこともできます。

DEC ID @ AS AS SELECT SELECT @ID =テーブルからのテーブルID(NOLOCK)WHERE fieldValue = @ newValue IF @idがNULL BEGIN SET TRANSACTION ISOLATIONレベルシリアル化可能SELECT @id = tableID FROMテーブルからWHERE fieldValue = @ newValue IF @IDがNULL BEGIN INSERT INTOテーブル(fieldValue)値(@newValue)SELECT @id = SCOPE_IDENTITY()END COMMITトランザクションTRANSACTION END SELECT @id

なぜISOLATION LEVEL SERIALIZABLEが必要なのか、シリアル化可能なトランザクションの中にいるとき、テーブルにヒットした最初のSELECTはレコードがあるべき場所をカバーする範囲ロックを作成します。

ISOLATION LEVEL SERIALIZABLEがないと、デフォルトの分離レベル(READ COMMITTED)は読み取り時にテーブルをロックしません。そのため、SELECTとUPDATEの間に誰かが挿入することができます。 READ COMMITTED分離レベルを持つトランザクションは、SELECTをロックしません。 REPEATABLE READSを使用したトランザクションは、レコードが見つかった場合はロックしますが、ギャップはロックしません。


31


存在する場合(SELECT 1 FROMテーブルのWHERE FieldValue = '')BEGIN SELECTテーブルIDのFROMテーブルWHERE FieldValue = '' INSERT INSERT INTOテーブル(FieldValue)の値( '')SELECT SCOPE_IDENTITY()AS TableID END

IF ELSEの詳細については、http://msdn.microsoft.com/ja-jp/library/ms182717(SQL.90).aspx[here]を参照してください。

注:これを二重チェックするのに便利なSQL Serverインストールなしで書かれていますが、私はそれが正しいと思います

また、SCISE_IDENTITY()ビットもアイデンティティだけを返すように変更している限り、EXISTS内で何が返されるかを気にしないので、EXISTSビットをSELECT *ではなくSELECT 1を実行するように変更しました。 TableIDがidentity列であると仮定


7


あなたは近かった:

IF EXISTS(SELECT * FROMテーブルWHERE FieldValue = '')SELECTテーブルID FROMテーブルWHERE FieldValue = '' ELSE BEGINテーブルに挿入テーブル(FieldValue)値( '')SELECTテーブルID FROMテーブルWHERE TableID = SCOPE_IDENTITY()


2


`if …​ else..endif`の構造を多少変更する必要があります。

存在する場合(FieldValue = ''の場合はTableから*を選択)、次にFieldValue = ''の場合はTableからTableIDを選択し、それ以外の場合はTable(FieldValue)の値に挿入を開始する( '')TableID = scope_identity()の場合はTableIDから選択する

あなたもすることができます:

存在しない場合(FieldValue = ''の場合はTableから*を選択)、Table(FieldValue)の値への挿入を開始する( '')FieldValue = ''の場合はTableからTableIDを選択する

または

存在する場合(FieldValue = ''の場合はTableから*を選択)、FieldValue = ''の場合はTableからTableIDを選択し、それ以外の場合はTableIDとしてtable(FieldValue)の値に挿入を開始


2


テーブルにキーがないようです。 あなたは単純に INSERT`を試すことができるはずです:それが重複しているなら、キー制約は噛み付き、 INSERT`は失敗します。 心配する必要はありません。アプリケーションがエラーを認識または無視しないようにする必要があります。 「主キー」と言うときは、おそらく「IDENTITY」値を意味します。 これで大丈夫ですが、キーの制約も必要です(例: あなたの自然なキーに UNIQUE)。

また、私はあなたの手術がやり過ぎているのだろうかと思います。 それぞれ「作成」アクションと「読み取り」アクションに別々の手順を使用することを検討してください。


1


DECLARE @ t1 TABLE(テーブルID int IDENTITY、フィールド値varchar(20))

 -  <<空の文字列が存在しない場合(SELECT * FROM @ t1 WHERE FieldValue = '')BEGIN SELECTテーブルID FROM @ t1 WHERE FieldValue = '' END ELSE BEGIN INSERT @ @ t1(FieldValue)VALUES( '')SELECT SCOPE_IDENTITY( )AS TableID END

 -  <<空の文字列を持つレコードがすでに存在する場合(SELECT * FROM @ t1 WHERE FieldValue = '') ')TableIDとしてSCOPE_IDENTITY()を選択しますEND


1


OBJECT_ID( 'tableName.put_fieldValue'、 'P')がNOT NULLの場合、proc tableName.put_fieldValueを作成します。procreateを作成します。tableName.put_fieldValue(@fieldValue int)宣言として使用します。 @tableid = 0がtable(fieldValue)値への挿入を開始する( '')場合は、fieldValue = ''の表から選択@tableid = scope_identity()end return @tableid go宣言@tablid int = 0 exec @tableid = tableName.put_fieldValue() 「」