読者です 読者をやめる 読者になる 読者になる

ADO.NET で IN演算子

.NET

ADO.NET 1.x でいい解決方法が見つからなかった問題が、ADO.NET 2.0 でも解決できなかったのでメモ。

テーブル Table1 のデータがこんな感じの場合、

 ID    NAME
 1     name1
 2     name2
 12    name1,name2

NAME が name1 または name2 のデータをSELECTしようとして、以下のように書くと意図しない結果になる。

string constr = @"Data Source=.\sqlexpress;Initial Catalog=testdb;Integrated Security=True";
using (SqlConnection con = new SqlConnection(constr)) {
    SqlCommand command = new SqlCommand();
    command.Connection = con;
    command.CommandText = "SELECT * FROM Table1 WHERE NAME IN (@name)";
    SqlParameter param = new SqlParameter("@name", SqlDbType.NVarChar);
    param.Value = "name1,name2";
    command.Parameters.Add(param);

    SqlDataAdapter adapter = new SqlDataAdapter(command);
    DataTable dt = new DataTable();
    adapter.Fill(dt);
}
----- DataTable の中身 -----
 ID    NAME
 12    name1,name2

SqlCommand の生成部分を以下のようにすると、意図した結果になる。

    SqlCommand command = new SqlCommand();
    command.Connection = con;
    command.CommandText = "SELECT * FROM Table1 WHERE NAME IN (@name1,@name2)";
    SqlParameter param1 = new SqlParameter("@name1", SqlDbType.NVarChar);
    param1.Value = "name1";
    command.Parameters.Add(param1);
    SqlParameter param2 = new SqlParameter("@name2", SqlDbType.NVarChar);
    param2.Value = "name2";
    command.Parameters.Add(param2);
----- DataTable の中身 -----
 ID    NAME
 1     name1
 2     name2

IN演算子の中のパラメータ数が固定ならこれでも問題ないが、そんなことはまずないと思うので以下のように動的にパラメータを生成すると良い。多分キャッシュも効くはず。
今のところこれ以上の解決方法が思いつかない。

    SqlCommand command = new SqlCommand();
    command.Connection = con;
    string[] targets = new string[] { "name1","name2" };
    string[] paramNames = new string[targets.Length];
    for (int i = 0; i < target.Length; i++) {
        paramNames[i] = "@name" + i;
        SqlParameter param = new SqlParameter(paramNames[i], SqlDbType.NVarChar);
        param.Value = targets[i];
        command.Parameters.Add(param);
    }
    string sql = "SELECT * FROM Table1 WHERE NAME IN ({0})";
    command.CommandText = string.Format(sql, string.Join(",", paramNames));
----- DataTable の中身 -----
 ID    NAME
 1     name1
 2     name2