3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.Net)DataTable.Selectの条件は引用符でくくらないとおかしなことになる

DataTable.Selectメソッドを使って、データの抽出を行ってました。

下記のように検索対象の列は文字列型ですが、中身は数値が入っています。

string strNo = "10";

 

DataTable tbl = new DataTable();

tbl.Columns.Add("no");

tbl.Columns.Add("name");

 

tbl.Rows.Add(new object[] { "1", "hoge" });

tbl.Rows.Add(new object[] { "10", "hoge" });

tbl.Rows.Add(new object[] { "2", "hoge" });

tbl.Rows.Add(new object[] { "20", "hoge" });

 

DataRow[] rows = tbl.Select("no=" + strNo);

検索値を 10 とすると以下のような例外が select メッソド実行時に発生します。

System.ArgumentException がキャッチされました

Message="Range オブジェクトの Min (1) は、 max (-1) 以下でなければなりません。"

Source="System.Data"

StackTrace:

場所 System.Data.Select.GetBinaryFilteredRecords()

場所 System.Data.Select.SelectRows()

場所 System.Data.DataTable.Select(String filterExpression)

場所 Hoge.hoge() 場所 D:\mydoc\devlop\hoge.cs:行 12

InnerException:

ちなみに、検索値を他の値に設定するとこのエラーが出ません。

で、原因を調べた結果、MSDNフォーラム: VB2005 .NET2.0 DataTable.Select()メソッドに関してに答えが。。

ほぼコピペですが、詳しい話を。。

DataTable.Selectメソッドの内部ではバイナリサーチ(二分探索)を使っているようです。

イナリサーチは、一旦リストをソートしてから出ないと実行できません。

検索列は文字列型なので、ソートすると下記のようになります。(文字列上の昇順になるわけです)

1,10,2,20

イナリサーチはソートしたリストから中央の値を検索値と比較して、検索したい値が中央の値の右にあるか、左にあるかを判断するので、この場合、2番目以降(値10)に値があると判断されます。

そして、10の値がどこまで続いているかを調べるためにバイナリサーチではもう一回検索されるわけですが、その時検索値の 10 とリスト内の 2 が比較された結果、10 > 2となり、DataTable内の "2" と "20" の間に 10 があるはずだとなって、エラーになるようですね。

対策として、下記のようにSelectメソッドの検索値に引用符(シングルクォーテーション)を付けて明示的に文字列だとすればこのエラーは回避できます。

DataRow[] rows = tbl.Select("no='" + strNo + "'");

文字列検索するときは引用符の付け忘れに注意しましょう。

引用符つけなくても一応動いてしまうので厄介です。

参考:

DataTable.Select の条件式での型推論による弊害