おそらく長いユーザー名のリスト(1から数千のユーザー名)を指定して、レコードのリストをロードしたいと思います。名前の選択方法を無視し、データベース内の既存のデータから名前を判別できないと想定します。これはSQLServer2005に適用されます。
特に、where句に数千の式を含む単一のselectステートメントを使用しないようにします。これにより、SqlCommandオブジェクトのコマンドテキストが非常に長くなります(例)。合理的に聞こえますか?...where n='bob000001' or n='bob000002' or ... or n='bob003000'
単純なテーブル変数にユーザー名を入力し、テーブル変数とテーブルとユーザーデータの間で選択/結合を実行して、選択を実行することにしました。
したがって、最初に行う必要があるのは、テーブル変数にデータを入力することです。ここでいくつか問題があります:
- SQL Server 2008より前のT-SQL構文は、単一のステートメントでテーブルに複数の行を挿入するために冗長であり、複数のselectやunionallsなどが必要です。
- SS2005の冗長な構文、またはSQL Server 2008で使用可能な簡潔な構文を使用するのではなく、長いコマンドテキストを完全に避け、単一の接続で複数のコマンドを使用するだけです。
- 1つのSqlCommandでテーブル変数を宣言すると、後続のSqlCommandで使用しようとすると、「スカラー変数を宣言する必要があります」というエラーが発生します。
- 何らかの方法でストアドプロシージャを含めると、依然として巨大な文字列を渡す必要がある場合や、変数がストアドプロシージャの範囲外に存続するのを妨げる場合があります。ストアドプロシージャの作成はオプションではないと想定します。
その3番目のポイントは、私が今解決しようとしている問題です。私は、人々(主張する)がエラーなしで単一のSqlCommandで変数を正常に宣言して使用する例を見てきました。複数のSqlCommandインスタンスを使用する場合、これをどのように実現できますか?変数は、複数のコマンドにまたがる単一の接続に対して存続することを読みました。何らかの形でトランザクションの助けを伴う可能性がありますか?
最後に、一時テーブルは使用したくないことを覚えておいてください。そうすることで簡単な解決策が提供されますが、変数と複数のSqlCommandsに関して私が尋ねている質問も回避できます。ただし、それが最善の選択肢であると本当に思われる場合は、遠慮なくそう言ってください。
何が起こっているかを示すコードスニペットは次のとおりです。
public static List<Student> Load( SqlConnection conn, List<StudentID> usernames )
{
//Create table variable
SqlCommand command = new SqlCommand( "declare @s table (id varchar(30))", conn );
command.ExecuteNonQuery();
//Populate a table variable with the usernames to load
command = new SqlCommand( "insert into @s (id) values (@p)", conn );
command.Parameters.Add( "@p", SqlDbType.VarChar );
int len = usernames.Count;
for (int i = 0; i < len; i++)
{
command.Parameters["@p"].Value = usernames[i].ToString();
command.ExecuteNonQuery(); //ERROR: must declare scalar variable @s
}
//Select all students listed in the table variable
command = new SqlCommand( "select StudentID, FName, LName, [etc.] from Student inner join @s on StudentID = @s.id order by StudentID", conn );
//Execute the query to get the student info from the database.
List<Student> students = new List<Student>()
using(SqlDataReader reader = command.ExecuteReader())
{
//code to load results and populate students list
}
return students;
}
注:パラメーターを含むSqlCommandは、ストアドプロシージャを内部的に呼び出すことを認識しています。これにより、通常、複数のSqlCommand間で変数を永続化できなくなりますが、テーブル変数を宣言する最初のクエリにはパラメーターが含まれません(つまり、command.Parametersへの参照はありません)。 AddWithValueが作成されます)。したがって、ストアドプロシージャを呼び出す可能性のある後のコマンドのスコープ内にある必要があります。
@
編集:一時テーブルを使用するには、 sを#
sに、declare @
sテーブルをsに変更するだけcreate table #
です。これは便利です。最後に一時テーブルを削除することもできますが、必須ではありません。