1.21 jigowatts

Great Scott!

ADO.NET IN句にSqlParameterCollection.AddWithValue メソッドを使う

概要

ADO.NETでIN句にパラメータを渡しても動かないという話を聞き、試してみたところ確かに想定した結果にならない!

検証

■データ
f:id:sh_yoshida:20160129005051p:plain
■ソース

using System;
using System.Data.SqlClient;

namespace AdonetParameter
{
    class Program
    {
        static void Main(string[] args)
        {
            string connectionString =
                "Data Source=(localdb)\\v11.0;initial catalog=Simple;"
                        + "Integrated Security=true";

            string queryString =
                "SELECT * from dbo.myTable "
                    + "WHERE Name IN (@param) ";


            string paramValue = "Test01,Test03,Test04";

            using (SqlConnection connection =
                new SqlConnection(connectionString))
            {
                SqlCommand command = new SqlCommand(queryString, connection);
                command.Parameters.AddWithValue("@param", paramValue);

                try
                {

                    connection.Open();
                    SqlDataReader reader = command.ExecuteReader();
                    while (reader.Read())
                    {
                        Console.WriteLine("\t{0}\t{1}\t{2}",
                            reader[0], reader[1], reader[2]);
                    }
                    reader.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            }

            Console.ReadKey();
        }
    }
}

実行結果はデータがなにも取得できず。
指定した3つの値それぞれに一致する結果を取得する想定でしたが、そもそもSqlParameterはSQLインジェクション対策なので、一つの値として扱われているのでしょうね。

string queryString =
    "SELECT * from dbo.myTable "
        + "WHERE Name IN (@param) ";

string paramValue = "Test01,Test03,Test04";

動的にパラメータを作るしかないかなと思っていたのですが、とあるブログ様*1でクエリを組み替えてLike句にすることで解決してました!
2017/9/12 コメントでご指摘いただき修正しました。

string queryString =
        "SELECT * from dbo.myTable "
            + "WHERE ',' + @param + ',' like '%,' + Name + ',%' ";

■実行結果

        1       Test01  10
        3       Test03  30
        4       Test04  40

まとめ

柔軟な考え方って大切。

■補足:EFでのIN句実装

using (var context = new Model1()) 
{
    string[] paramValue = {"Test01","Test03","Test04" };
    var data = context.myTables.Where(c => paramValue.Contains(c.Name));
    foreach (var item in data)
    {
        Console.WriteLine("\t{0}\t{1}\t{2}",
                item.Id, item.Name, item.Value);
    }
}

*1:勝手にリンクを張るのは気が引けるので控えます。ぐぐればすぐ見つかるはず!