2012-01-16 2 views
10

次のコードがストアドプロシージャにあります。スクリプトが並列実行されているときに#tempテーブルのPKを作成できません

.... 
select ... into #temp from .... 
alter table #temp add constraint PK_mytemp13 primary key (....) 
.... 

ストアドプロシージャを並列実行すると、次のエラーメッセージが表示されることがあります。

データベースには、すでに 'PK_perf322dsf'という名前のオブジェクトがあります。 制約を作成できませんでした。以前のエラーを参照してください。

以下の方法で回避できると思います。他のより洗練されたソリューションがありますか?

  1. 最初に主キーを使用してテンポラリテーブルを作成します。次に、行を挿入します。
    create table #temp (... primary key (....))

  2. 動的にセッションIDを使用してPKを作成します。
    declare @s varchar(500) = 'alter table #temp add constraint PK_temp' + @@spid + ' primary key (....)

答えて

3
  1. あなたは
  2. 、(代わりにグローバルな一時テーブルの、不可能である)異なる接続から同じ一時テーブルに挿入しようか、に挿入してみてください異なるテーブル。

第二場合 - あなたは、単純に次の操作を行うこと - PRIMARY KEY(...)を追加#TEMP ALTER TABLEを

第一場合 - あなたは前にキーで(定期的または一時的なグローバル)テーブルを作成する必要がありますパラレル操作で使用する場合

+2

このエラーは、ローカルtempテーブルの作成、コードブロック内に名前付き主キーを作成し、そのコードブロックを呼び出す接続が2つ以上ある場合に発生します。 SQL Serverでは、ローカルの一時テーブルでも同じ名前の2つのPKを許可しません。 – CDC

11

これは、2つの異なる呼び出しに対して同じクライアント接続インスタンシエーション(1つのSPIDまたはSQL Serverの接続に相当)を再使用する場合にのみ発生します。私は決してきたん

上無視:二つの平行な呼び出しが

のSPIDは、ローカル(単一#TEMPテーブル)で互いから完全に隔離されている

編集を別の接続インスタンスと別のSPIDが持っている必要があります前に一時テーブルの名前付き制約。インデックスが必要なときにインデックスを使用するか、列の後にPRIMARY KEYを追加するだけです。制約名はsys.objectsのデータベース固有です

基本的に一意ではないクラスタ化インデックスです。インデックス名はsys.indexesのテーブルに一意のであるため、代わりにCREATE UNIQUE CLUSTERED INDEXを使用してください。

これは

CREATE TABLE #gbn (foo int NOT NULL); 
ALTER TABLE #gbn ADD CONSTRAINT PK_gbn PRIMARY KEY (foo); 

メッセージ2714、レベル16、状態5、行2
2つのSSMSクエリウィンドウで実行すると、データベースに 'PK_gbn' という名前のオブジェクトが既に存在し失敗しました。
メッセージ1750、レベル16、状態0、行2
制約を作成できませんでした。以前のエラーを参照してください。

不思議なことに、あなたのエラーとは異なり、エラーおよび制約名が一致し

これは私がこれを行う方法を覚えしようとしていたが、あなたは無名の主キーを作成することができます

CREATE TABLE #gbn (foo int NOT NULL); 
CREATE UNIQUE CLUSTERED INDEX PK_gbn ON #gbn (foo); 
+0

@MartinSmith:エラーから、制約名は無視されています。 IIRCでは、私がインデックスを作成したとき(PKではない)、一時テーブルに多くのアンダースコアといくつかの16進数が追加されます。私は並行性の問題を経験したことがありません。私は、エラーがテンポラリテーブルの処理の周辺ではないことを示唆しています。 – gbn

+0

名前付き制約は、 'sys.objects'で一意であるため、tempdbで一意に名前を付ける必要があります。名前付きインデックスは必ずしもそうである必要はありません。実際には、OPはたぶんユニークなインデックスまたはunamed制約を使用するだけです。 (編集:しかし、エラーメッセージについてはどういう意味か...) –

+0

@MartinSmith:ちょうどそれを確認しました。更新を参照してください。私は一時テーブルで名前付き制約を使用することについて考えたことはありません。常に永続的なテーブルで行う – gbn

8

の作品このエラーを回避してください。これは、1つ以上の列をサポートするので、列レベルのPKを置くこととは異なります。次に例を示します。

CREATE TABLE #test 
(
    AccountNumber INT NOT NULL, 
    TransactionNumber INT NOT NULL, 
    PRIMARY KEY CLUSTERED (tranid, sys_process_dt) 
); 

これにより、最終的な目標と名前の重複が防止されます。クエリは、SQL Serverがsys.sysobjectsにあなたのためのPKの名前でGUIDを置くことが表示されます:

SELECT * 
FROM tempdb.sys.sysobjects 
WHERE name LIKE '%#test%' 

名前を| XTYPE

--------------------------------

#test ___..._ 000000000407 | U

PK __#test_____B88A05A770B3A6A6 | PK

ケーキを食べて食べることもできます。

関連する問題