SQL Server UDF の呼び出し間で状態を維持できますか?
-
09-06-2019 - |
質問
データを挿入する SQL スクリプトがあります (現在数千の INSERT ステートメントを介して)。列の 1 つに、実際にはいくつかの異なるテーブル間で一意である一意の識別子 (IDENTITY 型ではなく、単なる単純な int) が含まれています。
次に利用可能な ID (つまり、最後に使用した ID + 1) ですが、UDF 内からグローバル変数または静的変数を使用する方法がないようで、一時テーブルも使用できないため、これが可能かどうかわかりません。関数内から永続テーブルを更新しないでください。
現在、私のスクリプトは次のようになります。
declare @v_baseID int exec dbo.getNextID @v_baseID out --sproc to get the next available id --Lots of these - where n is a hardcoded value insert into tableOfStuff (someStuff, uniqueID) values ('stuff', @v_baseID + n ) exec dbo.UpdateNextID @v_baseID + lastUsedn --sproc to update the last used id
しかし、私はそれを次のようにしたいと思っています:
--Lots of these insert into tableOfStuff (someStuff, uniqueID) values ('stuff', getNextID() )
オフセットのハードコーディングは面倒な作業であり、エラーが発生しやすくなります。それを単純なスカラー関数にパッケージ化することは非常に魅力的ですが、呼び出し間のオフセット カウンターを維持する方法がないようなので、そのようにはできないと思い始めています。そうですか、それとも私に何か足りないことがありますか。
現在 SQL Server 2005 を使用しています。
明確にするために編集:
2 人のユーザーがそれを押すことは起こりません。これは一度だけ実行されるアップグレード スクリプトであり、同時に実行されることはありません。
実際の sproc には sp_ というプレフィックスが付いていません。コード例を修正しました。
通常の使用法では、必要に応じて ID テーブルと sproc を使用して ID を取得します。私はこのスクリプトでそれを行うためのよりクリーンな方法を探していました。基本的には大量のデータをデータベースにダンプするだけです。
解決
呼び出し間でオフセットカウンターを維持する方法がないようなので、そのようにはできないと思い始めています。そうですか、それとも私に何か足りないことがありますか。
あなたには何も欠けていません。SQL Server はグローバル変数をサポートしておらず、UDF 内のデータ変更もサポートしていません。たとえ CONTEXT_INFO を使用するような厄介なことをしたかったとしても (「 http://weblogs.sqlteam.com/mladenp/archive/2007/04/23/60185.aspx)、いずれにせよ、UDF 内からそれを設定することはできません。
オフセットを変数にしてその反復をループし、そのループ内で挿入を行うことで、オフセットの「ハードコーディング」を回避する方法はありますか?
他のヒント
2人のユーザーが同時にそれを押すと、同じIDが取得されます。なぜ代わりに ID を持つ ID テーブルを使用しなかったのですか。それに挿入して、それを一意の (保証された) ID として使用します。これにより、パフォーマンスも大幅に向上します。
sp_getNextID
proc の前に sp_ を付けることは絶対にしないでください。オプティマイザは最初にマスター DB をチェックしてその proc がそこに存在するかどうかを確認し、次にローカル DB をチェックするため、これはパフォーマンスに影響します。また、MS がサービス パックで sp_getNextID を作成することを決定した場合、あなたのものは決して実行されません。
おそらく価値以上に手間がかかるでしょうが、SQL CLR UDF では静的な C#/VB 変数を使用できるので、UDF が更新されるたびにこの変数をインクリメントするだけで、やりたいことができると思います。と呼ばれた。もちろん、静的変数は、アプリドメインがアンロードされるたびに失われます。したがって、ある日から次の日まで ID の継続性が必要な場合は、NextId への最初のアクセス時に、この ID を使用するすべてのテーブルをポーリングして最高値を見つける方法が必要になります。