また妙なところでやられました。
時々、共通処理なんかのロジックで動的な 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 ファイルの中身が妥当でない)
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
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
うーん。気をつけましょう。