none
VB2005 .NET2.0 DataTable.Select()メソッドに関して

    質問

  • こんにちは初めて質問します。

    早速なのですが、

    DataTableのSelectメソッドに関して質問します。

    DataTableの列が文字列型で数値の文字列が入っている場合

    Selectメソッドにて一重引用符を囲まない形でFilterを指定すると(ex "Num = 1")

    データを取得できる場合と、出来ない場合があります。

    出来ない場合は
    "Range オブジェクトの Min (8) は、 max (-1) 以下でなければなりません。"
    とメッセージが出ます。

    このエラーの原因を知りたいのです。

    なぜ出来るのと出来ないのがあるのか?

    以上です。

    皆さんのご協力よろしくお願いします。
    2009年9月29日 6:31

回答

  • 回答ではありませんが、同じ内容が以下で交わされていました。結局、結論は出ていません。通常はキャストされてうまくいくと思うのですが、なぜか特定の値に関してはエラーになるようです。

    ArgumentException in DataTable Select statement
    http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/d7e152a9-c700-4cf7-9c9a-68bc642faa16

    #コネクトも検索してみたかったのですが、なぜか検索キーワードを入力する画面が出ず、いきなり全件表示されてしまいます・・・


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク 菊地俊介 2009年10月21日 9:35
    2009年9月29日 8:09
    モデレータ
  • 列の削除は関係ありませんでした。
    次のスレッドで nobugz という方が原因を書かれていました。

    Min (5) must be less than or equal to max (-1) in a Range object
    http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/aa45873f-5374-47c0-b5ed-a31c2e1fab32/#14cf0ef6-1759-4192-aca2-0a15b75d5589


    これをふまえると、たとえば次のコードでもエラーが再現できます。

    Dim dt As DataTable = New DataTable()
    dt.Columns.Add("col", GetType(String))
    For Each value As String In New String() {"1", "2", "10", "20"}
        dt.Rows.Add(value)
    Next
    'ArgumentException:
    'Range オブジェクトの Min (1) は、max (-1) 以下でなければなりません。
    dt.Select("col = 10")


    一応説明します。
    Select の内部では、2回のバイナリサーチ(二分探索)により該当データが絞り込まれます。
    このバイナリサーチでは、列の値を「文字列」としてソートしたインデックスが使用されます。これは、列 "col" の型が String だからです。
    このインデックスは次のように並べられます("10" < "2" なので)。

    1
    10
    2
    20

    このインデックスに対してバイナリサーチが行われるのですが、その際の値の比較操作は「数値」で行われます。これは、Select の絞り込み条件の 10 の値がクォーテーションで囲まれていないためです。

    すると、条件に該当する範囲の先頭行を特定する1回目のサーチでは、10 が運良く2行目(インデックス番号 1)に見つかるのですが、最終行を特定する2回目のサーチでは、10 が見つからずに今回のエラーになります。これは、数値として 10 と 2 が比較されることで 10 > 2 となり、文字列で並んでいる "2" と "20" の範囲側に 10 が存在するはずだという探索になるためです。

    同じ原因から別の現象にもつながります。
    以下のコードではエラーは発生しませんが、結果は「該当なし」になります。

    Dim dt As DataTable = New DataTable()
    dt.Columns.Add("col", GetType(String))
    For Each value As String In New String() {"1", "2", "10"}
        dt.Rows.Add(value)
    Next
    If dt.Select("col = 2").Length = 0 Then MsgBox("該当なし")


    本来は Select("col = '2'") とするか Select("convert(col, 'System.Int32') = 2") とすべきところなのかもしれないので Select のバグかというと微妙ですが、親切ではなく、問題を引き起こす可能性が高い仕様だと私は思いました。

    ただ、この原因、スレッド「DataTable.Select の結果がおかしい」の説明にはなりませんけど...。

    • 回答としてマーク 菊地俊介 2009年10月21日 9:35
    2009年10月7日 12:04

すべての返信

  • 回答ではありませんが、同じ内容が以下で交わされていました。結局、結論は出ていません。通常はキャストされてうまくいくと思うのですが、なぜか特定の値に関してはエラーになるようです。

    ArgumentException in DataTable Select statement
    http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/d7e152a9-c700-4cf7-9c9a-68bc642faa16

    #コネクトも検索してみたかったのですが、なぜか検索キーワードを入力する画面が出ず、いきなり全件表示されてしまいます・・・


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク 菊地俊介 2009年10月21日 9:35
    2009年9月29日 8:09
    モデレータ
  • 今作成中のアプリケーションで DataTable.Select が思ったように機能しなかったため調査していたところ、作成した再現コードにて Maboroshi さんと同じエラーが発生する場合がありました。

    DataTable.Select の結果がおかしい」という投稿をしました。
    (こちらにぶら下げようかと思ったのですが、タイトルにて VB + .NET2.0 と限定されていたので、別スレッドにしました。)

    マルチスレッドなど、他にも要因はあるかもしれませんが、Maboroshi さんのコードでも列の削除を行われていないでしょうか?

    2009年10月5日 5:37
  • 列の削除は関係ありませんでした。
    次のスレッドで nobugz という方が原因を書かれていました。

    Min (5) must be less than or equal to max (-1) in a Range object
    http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/aa45873f-5374-47c0-b5ed-a31c2e1fab32/#14cf0ef6-1759-4192-aca2-0a15b75d5589


    これをふまえると、たとえば次のコードでもエラーが再現できます。

    Dim dt As DataTable = New DataTable()
    dt.Columns.Add("col", GetType(String))
    For Each value As String In New String() {"1", "2", "10", "20"}
        dt.Rows.Add(value)
    Next
    'ArgumentException:
    'Range オブジェクトの Min (1) は、max (-1) 以下でなければなりません。
    dt.Select("col = 10")


    一応説明します。
    Select の内部では、2回のバイナリサーチ(二分探索)により該当データが絞り込まれます。
    このバイナリサーチでは、列の値を「文字列」としてソートしたインデックスが使用されます。これは、列 "col" の型が String だからです。
    このインデックスは次のように並べられます("10" < "2" なので)。

    1
    10
    2
    20

    このインデックスに対してバイナリサーチが行われるのですが、その際の値の比較操作は「数値」で行われます。これは、Select の絞り込み条件の 10 の値がクォーテーションで囲まれていないためです。

    すると、条件に該当する範囲の先頭行を特定する1回目のサーチでは、10 が運良く2行目(インデックス番号 1)に見つかるのですが、最終行を特定する2回目のサーチでは、10 が見つからずに今回のエラーになります。これは、数値として 10 と 2 が比較されることで 10 > 2 となり、文字列で並んでいる "2" と "20" の範囲側に 10 が存在するはずだという探索になるためです。

    同じ原因から別の現象にもつながります。
    以下のコードではエラーは発生しませんが、結果は「該当なし」になります。

    Dim dt As DataTable = New DataTable()
    dt.Columns.Add("col", GetType(String))
    For Each value As String In New String() {"1", "2", "10"}
        dt.Rows.Add(value)
    Next
    If dt.Select("col = 2").Length = 0 Then MsgBox("該当なし")


    本来は Select("col = '2'") とするか Select("convert(col, 'System.Int32') = 2") とすべきところなのかもしれないので Select のバグかというと微妙ですが、親切ではなく、問題を引き起こす可能性が高い仕様だと私は思いました。

    ただ、この原因、スレッド「DataTable.Select の結果がおかしい」の説明にはなりませんけど...。

    • 回答としてマーク 菊地俊介 2009年10月21日 9:35
    2009年10月7日 12:04
  • 皆様、こんにちは。

    trapemiyaさん、回答ありがとうございます。

    TH01さん、詳しい説明を投稿していただき、ありがとうございます。

    Maboroshiさん、はじめまして。その後いかがでしょうか?
    疑問は解決しましたか?

    有用な情報と思われたため、勝手ながらtrapemiyaさん、TH01さんの回答へ回答マークをつけさせていただきました。

    今後ともフォーラムをよろしくお願いします。
    それでは!
    2009年10月21日 9:39