質問

現在、ユーザーがテーブルの 1 つのスキーマの一部を指示できるレガシー システムを更新しています。ユーザーは、このインターフェイスを通じてテーブルの列を作成したり、テーブルから列を削除したりできます。このレガシー システムは ADO 2.8 を使用し、データベースとして SQL Server 2005 を使用しています (この野獣を最新化する試みが始まる前にどのデータベースを使用していたのか知​​りたくもありません...しかし、私はそれます。=))

これと同じ編集プロセスで、ユーザーは、これらのユーザー作成フィールドに保存できる有効な値のリストを定義 (および変更) できます (ユーザーがフィールドに含めることができる値を制限したい場合)。

ユーザーがフィールドの有効なエントリのリストを変更するときに、有効な値の 1 つを削除すると、新しい「有効な値」を選択して、その (現在は無効な) 値が含まれる行をマップすることができます。それらは再び有効な値を持ちます。

古いコードを調べてみると、上記の変更はトランザクション内で行われないため、システムを無効な状態にすることに対して非常に脆弱であることに気付きました (したがって、上記のプロセスの途中で他の誰かがやって来て、自分自身の変化…まあ、それが引き起こす可能性のある問題は想像できるでしょう)。

問題は、単一のトランザクションでそれらを更新させようとしているのですが、コードがそのテーブルのスキーマを変更する部分に到達するたびに、他のすべての変更が行われてしまうことです(行内の値を更新するなど)。スキーマが変更されたテーブルかどうか...トランザクションのその時点までに作成されたテーブルがサイレントに削除されたように見えても、それらは完全に無関係なテーブルである可能性があります。それらが削除されたことを示すエラー メッセージは表示されず、最後にトランザクションをコミットしてもエラーは発生しません...しかし、トランザクションで更新されるはずのテーブルを見に行くと、新しい列だけがそこにあります。スキーマ以外の変更は保存されません。

ネットで答えを探すのは、今のところ数時間の無駄であることが判明しています...そこで私はここに助けを求めます。テーブルのスキーマの更新とテーブル内の行の更新 (同じテーブルであっても、他のテーブルであっても) の両方を行うトランザクションを ADO 経由で実行しようとした人はいるでしょうか?許可されていないのでしょうか?この状況で役立つドキュメントはありますか?

編集:

トレースを実行したところ、これらのコマンドがデータベースに送信されました (括弧内の説明)

(ここで何が起こっているのかわかりませんが、一時ストアド プロシージャを作成しているようです...?)


declare @p1
int set @p1=180150003 declare @p3 int
set @p3=2 declare @p4 int set @p4=4
declare @p5 int set @p5=-1

(ユーザー作成フィールドの定義情報を保持するテーブルの取得)


exec sp_cursoropen @p1 output,N'SELECT * FROM CustomFieldDefs ORDER BY Sequence',@p3 output,@p4 output,@p5 output select @p1, @p3, @p4, @p5
go

(私のコードはここにあるそれらのリストを反復処理して、現在の情報を取得していたと思います)


exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,1025,1,1
go
exec sp_cursorfetch 180150003,1028,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go

(ここで定義の変更されたデータを入力しているようです。それぞれを確認し、カスタム フィールド自体の定義で発生した変更を更新します)


exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=1,@Description='asdf',@Format='U|',@IsLookUp=1,@Length=50,@Properties='U|',@Required=1,@Title='__asdf',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=2,@Description='give',@Format='Y',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_give',@Type='B',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=3,@Description='up',@Format='###-##-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_up',@Type='N',@_Version=1
go 
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=4,@Description='Testy',@Format='',@IsLookUp=0,@Length=50,@Properties='',@Required=0,@Title='_Testy',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=5,@Description='you',@Format='U|',@IsLookUp=0,@Length=250,@Properties='U|',@Required=0,@Title='_you',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=6,@Description='never',@Format='mm/dd/yyyy',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_never',@Type='D',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=7,@Description='gonna',@Format='###-###-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_gonna',@Type='C',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go

(これは、この保存が開始される前に、私のコードがインターフェイスを通じて削除されたものを削除する場所です]...また、私が知る限り、このトランザクション中に実際に起こったのはこれだけです)


ALTER TABLE CustomizableTable DROP COLUMN _weveknown;

(ユーザーが作成した列のプロパティを変更したり、列のインデックスを追加/削除したりする必要があるなど、定義が変更された場合は、行にデフォルト値を与えるとともに、ここで変更が行われます。指定された列にはまだ値がありませんでした...私の知る限り、ストアド プロシージャの終了時に実際には何も起こらないことに注意してください。)

go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '__asdf'
go
ALTER TABLE CustomizableTable ALTER COLUMN __asdf VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON CustomizableTable ( 
__asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
select * from IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON 
CustomizableTable ( __asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
UPDATE CustomizableTable SET [__asdf] = '' WHERE [__asdf] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_give'
go
ALTER TABLE CustomizableTable ALTER COLUMN _give Bit NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__give') DROP INDEX idx__give ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_give] = 0 WHERE [_give] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_up'
go
ALTER TABLE CustomizableTable ALTER COLUMN _up Int NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__up') DROP INDEX idx__up ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_up] = 0 WHERE [_up] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_Testy'
go
ALTER TABLE CustomizableTable ADD _Testy VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__Testy') DROP INDEX idx__Testy ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_Testy] = '' WHERE [_Testy] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_you'
go
ALTER TABLE CustomizableTable ALTER COLUMN _you VarChar(250) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__you') DROP INDEX idx__you ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_you] = '' WHERE [_you] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_never'
go
ALTER TABLE CustomizableTable ALTER COLUMN _never DateTime NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__never') DROP INDEX idx__never ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_never] = '1/1/1900' WHERE [_never] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_gonna'
go
ALTER TABLE CustomizableTable ALTER COLUMN _gonna Money NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__gonna') DROP INDEX idx__gonna ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_gonna] = 0 WHERE [_gonna] IS NULL
go

(取引終了…?)

exec sp_cursorclose 180150003
go

上記の作業をすべて行った後は、列の削除のみが行われます。トランザクション内の前後はすべて無視されているようで、SQL トレースにはトランザクション中に問題が発生したことを示すメッセージはありませんでした。

役に立ちましたか?

解決

コードはサーバー側カーソルを使用しており、それがこれらの呼び出しの目的です。最初の呼び出しセットは、カーソルの準備/オープンです。次に、カーソルから行をフェッチします。最後にカーソルを閉じます。これらの sproc は、T-SQL ステートメントの OPEN CURSOR、FETCH NEXT、CLOSE CURSOR に似ています。

もっと詳しく調べる必要がありますが (そうするつもりです)、サーバー側のカーソル、カプセル化トランザクション、および DDL で何かが起こっているのではないかと思います。

さらにいくつかの質問:

  1. この場合、サーバー側カーソルを使用するつもりですか?
  2. ADO コマンドはすべて同じアクティブな接続を使用していますか?

アップデート:

何が起こっているのか正確にはわかりません。

サーバー側カーソルを使用しているようです。そのため、生成された SQL ステートメントを実行してスキーマを変更し、動的テーブル内のデータを更新することに加えて、Recordset.Update() を使用して変更をサーバーにプッシュできます。明示的なトランザクション内で同じ接続を使用します。

カーソル操作がトランザクションの残りの部分にどのような影響を与えるのか、あるいはその逆の影響があるのか​​はわかりません。正直に言うと、これが機能しないことに驚いています。

どのくらい大きな変更になるかわかりませんが、サーバー側のカーソルから離れて、テーブル更新用の UPDATE ステートメントを作成することをお勧めします。

申し訳ありませんが、これ以上お役に立てませんでした。

ところで、sp_cursor 呼び出しに関する次の情報を見つけました。

http://jtds.sourceforge.net/apiCursors.html

他のヒント

あなたが説明した動作は許可されています。コードはどのようにスキーマを変更しているのでしょうか?SQL をオンザフライで構築し、ADO コマンドを通じて実行しますか?それともADOXを使っているのでしょうか?

データベース サーバーにアクセスできる場合は、概要を説明したシナリオをテストしながら、SQL プロファイラー トレースを実行してみてください。トレースにエラー/ロールバックが記録されているかどうかを確認します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top