SqlCommandの一時テーブルとパラメーターの落とし穴
.NETのSqlCommandでローカル一時テーブルを作成する際、SQLにSqlParameterを含めると、直後のSqlCommandからその一時テーブルを参照できず、「オブジェクト名 '#temp' が無効です」というエラーが発生することがあります。 using SqlCommand comm1 = conn.CreateCommand(); comm1.CommandText = """ CREATE TABLE #temp (col INT NOT NULL); INSERT INTO #temp (col) VALUES (@param); """; SqlParameter param = comm1.CreateParameter(); param.ParameterName = "@param"; param.Value = 1; comm1.Parameters.Add(param); await comm1.ExecuteNonQueryAsync(); using SqlCommand comm2 = conn.CreateCommand(); comm2.CommandText = "SELECT col FROM #temp;"; // Microsoft.Data.SqlClient.SqlException: // オブジェクト名 '#temp' が無効です。 var value = await comm2.ExecuteScalarAsync(); 原因は、パラメーター化されたSQLがSQL Server側でsp_executesqlとして実行されるためです。sp_executesql内で作成されたローカル一時テーブルは、その実行スコープ内のものとして扱われ、スコープ終了時に破棄されます。そのため、次のSqlCommandからは参照できません。 対策としては、まずパラメーターを使わずにローカル一時テーブルの作成のみを実行し、その後パラメーター化されたSQLでデータを操作します。あるいは、作成から利用までをすべて1つのSqlCommand内で完結させる方法もあります。 ローカル一時テーブルを...