SQLのWHERE句で LIKE と * のあいまい検索 の書き方

タグの編集
投稿者 べんきょうちゅう  (社会人) 投稿日時 2014/9/27 21:02:58
Microsoft Visual Studio Express 2013 for Windows Desktop です。

  今 アクセスのテーブルの検索をしようとしています。

      Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ = @Code")    
    と WHERE句 にパラメータ を入れました。
   これは 無事 動きました。

   次に LIKE と *  で いわゆる 「あいまい検索」を試みました。


  1、 "SELECT * FROM T3 WHERE フォルダ = Like  " * " + @Code + " * " "

      追加情報:String "SELECT * FROM T3 WHERE フォルダ =" から型 'Double' への変換は無効です。 のエラー

  2、  "SELECT * FROM T3 WHERE フォルダ = Like  '*@Code*'"

    追加情報:クエリ式 'フォルダ = Like  '*@Code*'' の 構文エラー : 演算子がありません。 のエラー

  3、 パラメータをやめて 直接文字を入れてみても

    "SELECT * FROM T3 WHERE フォルダ = Like 'カフェ'"

    追加情報:クエリ式 'フォルダ = Like 'カフェ'' の 構文エラー : 演算子がありません のエラー

  4、 "SELECT * FROM T3 WHERE フォルダ = Like  " * " & 'カフェ' + " * ""
 
    追加情報:String "SELECT * FROM T3 WHERE フォルダ = Li" から型 'Double' への変換は無効で  のエラー

  5、"SELECT フォルダ FROM T3 WHERE フォルダ = Like " '" & "*" & @Code & "*" & "'""

     追加情報:クエリ式 'フォルダ = Like' の 構文エラー : 演算子がありません。 のエラー

   どれも一応ビルドは出来ました。のでSQL文の問題だと思うのですが??

    おそらく 私の無知からくる間違いがどこかにあると思うのですが途方にくれています。

    どうか 皆様のお知恵をお願いします。 
投稿者 ナシゴレン  (社会人) 投稿日時 2014/9/27 23:49:02
突っ込みどころ満載ですが、
まず、前提として、LIKEを使う場合、イコール(=)をつけてはいけません。

フォルダ = Like 

ではなく、

フォルダ Like 

です。
詳細は、以下の「6-2.LIKE演算子の使用」を見てください。
http://homepage1.nifty.com/rucio/main/VBdotNet/Database/Database8.htm
※ここではLIKE演算子のワイルドカードに%を使っていますが、
 Accessならばワイルドカードは*でいいんじゃないかな?

3、についてはこれで解決ですね。

あとは1、のパラメータの設定方法となりますが、@Codeに対するパラメータ文字列の中に*を含めてください。
(どのようなコードを書いているか分からないので、この程度のアドバイスになります。)

投稿者 るきお  (社会人) 投稿日時 2014/9/28 19:22:01
1つのSQL文は1つの文字列にしてください。

"SELECT * FROM T3 WHERE フォルダ = Like  " * " + @Code + " * " "


このVB上の式は、コードの色分けを見るとわかると思うのですが、 * が文字列の外にあり、単一の文字列になっていません。

* はかけ算の記号なので、この場合VBはかけ算を生成しようとしますが、 * の前後にあるものが計算できる数値ではないのでVBはこれをエラーにします。

このコードの場合、多分 * も含めてパラメーター @Codeの値に含むことになり、SQL文としては次のとおりになると思います。


LIKE演算を行う場合のパラメーター化については、対象のデータベース製品により仕様が異なる可能性があります。 * を使われているようなのでデータベースはAccessでしょうか?
SQL Serverであれば、%も含めてパラメーターの値にするようですが、Accessについては私はわかりません。

苦戦するようならばまずはパラメーター化を諦めて直接SQL文に値を埋め込んで動作することを確認してから、後でゆっくりパラメーター化していくという方法も良いかと思います。
投稿者 べんきょうちゅう  (社会人) 投稿日時 2014/9/28 23:31:59
 ナシゴレンさん るきおさん ご返事有難うございます。

  なるほど = と LIKE は 同じ役割だったんですね。思い込みで = LIKE と繋げてしまっていました。

これで ご指摘のとおり 3は解決 。

 あと * の件は 掛け算をしようとしていたのですね。 それで 「---'Double' への変換はーーー」のエラーが出ていたわけですか?
文字列の話なのに なぜ Double なの??? と思っていました。エラーの文面をもっと深く読み取るべきでした。
 と いっても 読み解ける自信はありませんが。

 「1つのSQL文は1つの文字列にしてください。」

この意味合いも言葉としては判るような感じですが いざ * と パラメータを埋め込んで書こうと思うと なかなか思うように行きません。

 おっしゃるとおり アクセス2000を使っております。アクセスではクエリーで割と楽に出来ましたが、VBとSQLではつまずいています。

 * を単なる文字ではなく かつ 掛け算記号でもなく 演算子? として 一つの文字列にする。
というような感じでよいのか? と思っています。

 いま あれこれ試していますが 解決にはいたっていません。

ナシゴレンさん るきおさん のご返事をよく読んで もう少しあがいてみます。

下にコードを上げておきます

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Database\Tag.mdb")
        Dim Cm As OleDbCommand = Cn.CreateCommand
        Adapter = New OleDbDataAdapter(Cm)
        Dim Builder As New OleDbCommandBuilder(Adapter)
        Dim Table As New DataTable

   ’<<<<<<<<<<<
        
        ' Cm.CommandText = ("SELECT フォルダ FROM T3 WHERE フォルダ  LIKE " '" & "*" & @Code & "*" & "'"")
                     ’LIKE の後ろに )が無いとオコラレル

                          ' 参考   "'" & "%" & txtUser.Text & "%" & "'"  SQLサーバー
                      '参考  Like "*" & [Forms]![F1]![T1] & "*"    アクセス

        'Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE  " * " & @Code & " * " ")
        'Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE  '*@Code*'")
        'Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE 'カフェ'")   ’OK
    'Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE @Code")    ’OK
    'Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE  ' * ' & 'カフェ' & ' * '")

  '<<<<<<<<<<<<<<<<< この部分でいろいろあがいています

        Dim sparam As OleDb.OleDbParameter
        sparam = New OleDb.OleDbParameter("@Code", SqlDbType.TEXT)
        sparam.Value = Me.TextBox1.Text
        Cm.Parameters.Clear()
        Cm.Parameters.Add(sparam)

        Adapter.Fill(Table)

        DataGridView1.DataSource = Table

        Table.Dispose()

    End Sub 
投稿者 ナシゴレン  (社会人) 投稿日時 2014/9/29 09:51:25
提示コードの

sparam.Value = Me.TextBox1.Text

の部分を、例えば

sparam.Value = "*" & Me.TextBox1.Text & "*"

にしてみてください。
これで、例えばMe.TextBox1.Text の内容が"カフェ"であれば、
@Codeの内容は"*カフェ*"になり、
Cm.CommandText = ("SELECT * FROM T3 WHERE フォルダ  LIKE @Code")
の構文が使えます。

あともう少しです。
投稿者 べんきょうちゅう  (社会人) 投稿日時 2014/9/29 12:17:21
ナシゴレンさん ご返事有難うございます

ご指摘のとおりテストをしてみました で結果は 抽出無し でした。

 sparam.Value = "*" & Me.TextBox1.Text & "*"

デバッグで見ると sparam.Valueは ちゃんと *カフェ*  となっています けれど、、、、、???

sparam.Value = "'*'" & Me.TextBox1.Text & "'*'" など (意味不明か?) やっても だめ ←は当たり前ですかね。

         'Cm.CommandText = "SELECT * FROM T3 WHERE フォルダ  LIKE "
         'Cm.CommandText = Cm.CommandText & "'" & "*" & @Code & "*" & "'"

が 有望そうに思えたのですが  @Code の@のところで 「、、、式が必要です。」のエラーがでて
ビルトが通りません。

 お気づきのことが在りましたらよろしくお願いします。」
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2014/9/29 15:10:56
「*」ではなく「%」ですよ。
Microsoft Access のクエリ画面とは、指定するワイルドカード文字が異なるので注意して下さい。

Access の mdb や accdb に OLE DB で接続する場合、
Like 演算子で利用可能なワイルドカードは以下のものとなります。

----------------------------------------
_          任意の1文字に一致します。
%          0文字以上の任意の文字列に一致します。
[_]        '_' に一致します。
[%]        '%' に一致します。
[[]        '[' に一致します。
[]]        ']' に一致します。
----------------------------------------

なお、Access のオプション設定で ANSI 92 SQL モードを
設定していた場合、Access からでも % 指定のモードになります。
(デフォルトでは ANSI 89 モードです)
投稿者 (削除されました)  () 投稿日時 2014/9/29 15:18:55
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2014/9/29 15:54:38
先ほどナシゴレンさんが指摘されていましたが、即効削除されたようなので後追いで指摘。

> DataGridView1.DataSource = Table
> Table.Dispose()

この部分、Dispose は不要です。
というよりも、利用中のオブジェクトを Dispose するのは不味いです。

Dispose は文字通り「破棄」の処理なので、Dispose するのなら、そのオブジェクトがどこからも(DataGridView からも)利用されてない状態になってから呼び出す必要があります。



――もっとも、DataTable や DataSet の Dispose メソッドには破棄処理が実装されていないので、実際のところ、Dispose を呼び出しても呼び出さなくても、動作に影響は無いのですけれどね。
投稿者 ナシゴレン  (社会人) 投稿日時 2014/9/29 16:10:31
ゴメンナサイ。
魔界の仮面弁士様のワイルドカードのご指摘で「しまった」と思い、
Disposeの言及だけ残そうと書き直しの文章を考えていたら、
この件についても、魔界の仮面弁士様のご指摘が先でした。
魔界の仮面弁士様、ありがとうございます。
投稿者 べんきょうちゅう  (社会人) 投稿日時 2014/9/29 17:44:25
 魔界の仮面弁士さん  ナシゴレンさん るきおさん ご返事有難うございます。

お蔭様で 解決にいたりました。本当に有難うございました。

 sparam.Value = "%" & Me.TextBox1.Text & "%" にて 無事検索OKとなりました。

 % は SQLサーヴァー専用だ と思っていました。

 = の件  * の件  SQL文に % を書くのではなくパラメータの所への設定の件  等々

思い込み と 調査不足が多いですね 頭が硬いナー でもこの間いろいろ調べたことが後になって役立てば

 と思っています。

 実は今 アクセス2000で作った物を こつこつと Microsoft Visual Studio Expressに移植しようとしています。

まだ 先は長いと思われますが また皆さんのお力を借りることもあると思います。

 よろしくお願いします。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2014/9/29 18:32:56
> 実は今 アクセス2000で作った物を
先の ANSI 89 と 92 の話は、Access 2000 以降で登場したものですね。
http://office.microsoft.com/ja-jp/access-help/HA010076601.aspx


> sparam.Value = "%" & Me.TextBox1.Text & "%" にて 無事検索OKとなりました。

良かったです。


ただし、厳密に言うと、それだけでは完全では無かったりします。

何故ならば、「%という文字を含むデータ」を検索するために、
TextBox に % と入れた場合、現状のコードだと『%%%』が検索される
わけですが、これだと % を含まないデータまで抽出されてしまうからです。

「%」を含むデータを探す場合には、先の回答にも書いたように、
『%[%]%』とする必要があります。

同様に、「_」や「[」なども対処が必要だったりします――本来は。
対応優先度は低いかもしれませんが、一応、頭の片隅にでも入れておいてください。



> SQLサーヴァー専用だ
SQL Server のことだとしたら、Microsoft の公式表記では、
サーヴァーではなくサーバーだったりしますが、それはさておき。

SQL Server や Oracle で上記「%」などの対応をする場合は、
 WHERE 列名 LIKE '果汁100\%%' ESCAPE '\'
のように、ESCAPE 句を使います。
(SQL Server では角括弧エスケープも使えますが)
投稿者 べんきょうちゅう  (社会人) 投稿日時 2014/9/29 19:14:59
 皆様 ご指導有難うございます。

 ESCAPEの件も有難うございます、MSの検索でひっかっからのですが、関係なしと見過ごしていました。

めったに無いことでしょうが一応頭に入れておきます。

 業務用では細かなところも手を抜けないのですね。 敬服です。

では