2007.08.22

SQLServer2005で動的SQLのエラーを取る場合の注意

また妙なところでやられました。

時々、共通処理なんかのロジックで動的な SQLが必要になることがあり、
次のような書き方をすることがありました。

Declare @sSql varchar(4000)
SET @sSQL = 'BULK INSERT ' + @sTableName
 + ' FROM ''c:\temp\' + @sTableName + '.csv'''
 + ' WITH ( FORMATFILE = ''c:\temp\' + @sTableName + '.fmt'' )'
Execute ( @sSQL ) -- 動的なSQLの実行
SELECT @iCheck= @@ERROR, @iCount= @@ROWCOUNT
If ( @iCheck <> 0 ) print @iCheck -- 取り込み失敗(ファイルが無い or ファイルの中身が妥当でない)

昔(SQLServer2000の頃)はこの書き方で、
csvファイルが無い場合でも、また取り込みの途中で 妥当でない行が見つかった場合でも、
同じようにエラーがちゃんと取得できていました。
いや、いま(SQLServer2005)でもこのコードをそのまま実行する分には期待通りの動作をします。

しかし、これを tryブロックの中に入れてしまったとたん、
csvファイルの中身がおかしくて取り込めなかった場合にエラーが取得できなくなります。
エラー番号が @@ERRORで取れない(常に0)のはもちろんですが、catchブロックにもまわりません。
csvファイルが無い場合などはちゃんと catchにまわります。
どうも severity の違いでエラーが取れたり取れなかったりするようです。


じゃぁ、どうすれば良いのか? なのですが、次のようにします。

Declare @sSql nvarchar(4000) -- nvarcharにする
Begin Try
SET @sSQL = N'BULK INSERT ' + @sTableName
 + N' FROM ''c:\temp\' + @sTableName + N'.csv'''
 + N' WITH ( FORMATFILE = ''c:\temp\' + @sTableName + N'.fmt'' )'
Execute ( @sSQL )
Execute @iCheck= sp_executesql @sSQL, N'' -- sp_executesqlを使って動的SQLの実行
SELECT /*@iCheck= @@ERROR,*/ @iCount= @@ROWCOUNT
If ( @iCheck <> 0 ) print @iCheck -- 取り込み失敗(ファイルの中身が妥当でない)
End Try
Begin Catch -- 致命的エラー(ファイルが無い)
print ERROR_NUMBER()
End Catch

うーん。気をつけましょう。

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
ichikawa