トップ回答者
事前に用意された複数項目(20個)から任意選択で検索しますが、AND検索がうまくいきません(OR検索は、OKです)。

質問
-
検索専用のフォーム画面があり、そこに選択項目が約20個用意されています。 そこから任意に選択した項目で検索します。 OR検索と、AND検索があります。 パラメタライズドクエリです。 Option Strict On設定です。 サーバー接続(SQL2000)、VB2010(Visual Studio 2010)使用です。
作成は、下記のようにしています。
1.OR検索:全項目を条件式に列挙し、選択していない項目は偽(False)になるようにしておきます。 これは、うまくいっています。
2.AND検索:全項目を条件式に書き、選択していない項目は真(True)になるようにしておきたいのですが、ここがうまくいきません。
以下は、AND検索でうまくいかないコードです、例えば下記のAND検索(1)のWhere以降の ”CustomerType=@CustomerType”(*)ですが、選択していないときはこれが真になるように設定したいのですが、@CustomerTypeに入れるものが分かりません。 とりあえず、全部(0 Or 1 Or 2 Or 3 Or 4 Or 9) を入れたり、Trueにしてみたりしました。 部分的にしか成功しません。 また、項目数を増やすと当然ながら正常動作しません。
また、この部分(*)をC(0),C(1),C(2),C(3)とするのが最善なのですが、これもうまくいきません(AND検索(2))。--ここでは、パラメタライズドクエリは後回しにしています。
解決策を、教えてください。
よろしく、お願いします。
YKsaila
以下は、コードです、3個あります。 最後の一個はうまくいっています。 初めの2個がうまくいきません。
AND検索(1):
If RB_AND.Checked = True Then 'AND検索
sql.CommandText = "SELECT Client_ID, ClientCode, CustomerType, VenderType, Area_ID, Staff_ID, Country_ID, ShortName, KanaCode, CompanyName, " _
& "Address1, Address2, Tel_in, E_mail, ClientStaffName, ClientStaffKana, Memo, Goods FROM T_M_Client " _
& "Where CustomerType=@CustomerType and VenderType= @VenderType and ClientCode= @ClientCode and KanaCode Like @KanaCode "
----省略
& "ORDER BY T_M_Client.Client_ID"
sql.CommandType = CommandType.TextIf Me.CB_CustomerType.Text = "" OrElse Me.CB_CustomerType.Text Is Nothing Then
'sql.Parameters.AddWithValue("@CustomerType", 0 Or 1 Or 2 Or 3 Or 4 Or 9)
sql.Parameters.AddWithValue("@CustomerType", True) ’選択しないとき、真になるようにしておきます。
Else
sql.Parameters.AddWithValue("@CustomerType", Me.CB_CustomerType.SelectedValue) ’選択したときの、実際の値
End IfIf Me.CB_VenderType.Text = "" OrElse Me.CB_VenderType.Text Is Nothing Then
'sql.Parameters.AddWithValue("@VenderType", 0 Or 1)
sql.Parameters.AddWithValue("@VenderType", True)
Else
sql.Parameters.AddWithValue("@VenderType", Me.CB_VenderType.SelectedValue)
End IfIf Me.TX_ClientCode.Text = " " Or Me.TX_ClientCode.Text Is Nothing Then
sql.Parameters.AddWithValue("@ClientCode", True)
Else
sql.Parameters.AddWithValue("@ClientCode", Me.TX_ClientCode.Text)
End IfIf Me.TX_KanaCode.Text = "" Or Me.TX_KanaCode.Text Is Nothing Then
sql.Parameters.AddWithValue("@KanaCode", True)
Else
sql.Parameters.AddWithValue("@KanaCode", "%" & Me.TX_KanaCode.Text & "%")
End Ifadapter.SelectCommand = sql
adapter.Fill(dsCombo)
dtCombo = dsCombo.Tables(0)'▼値の表示
DataGridView1.DataSource = dtCombo'▼後処理
dtCombo.Dispose()
adapter.Dispose()
sql.Dispose()
Con.Dispose()End If
AND検索(2):
If RB_AND.Checked = True Then 'AND検索
Dim C(20) As String ’Stringがいけないのでしょうか?
’C(0),C(1)の定義をします。Dim CID, VID As Integer
If Me.CB_CustomerType.Text = "" OrElse Me.CB_CustomerType.Text Is Nothing Then
C(0) = "1=1" ’選択しないとき、真になるようにしておきます。
Else
CID = DirectCast(Me.CB_CustomerType.SelectedValue, Integer)
C(0) = "CustomerType= " & CID & "" ’選択したときの、実際の値
End IfIf Me.CB_VenderType.Text = "" OrElse Me.CB_VenderType.Text Is Nothing Then
C(1) = "1=1"
Else
VID = DirectCast(Me.CB_VenderType.SelectedValue, Integer)
C(1) = "VenderType= " & VID & ""
End IfIf Me.TX_ClientCode.Text = " " Or Me.TX_ClientCode.Text Is Nothing Then
C(2)="1=1"
Else
C(2)= "KanaCode=Me.TX_ClientCode.Text"
End Ifsql.CommandText = "SELECT Client_ID, ClientCode, CustomerType, VenderType, Area_ID, Staff_ID, Country_ID, ShortName, KanaCode, CompanyName, " _
& "Address1, Address2, Tel_in, E_mail, ClientStaffName, ClientStaffKana, Memo, Goods FROM T_M_Client " _
'----省略
(A) & "Where C(0) and C(1) and C(2) " 'エラーがでます( 'C' は 関数名 として認識されません。)と表示。
sql.CommandType = CommandType.Textadapter.SelectCommand = sql
adapter.Fill(dsCombo)
dtCombo = dsCombo.Tables(0)'▼値の表示
DataGridView1.DataSource = dtCombo'▼後処理
dtCombo.Dispose()
adapter.Dispose()
sql.Dispose()
Con.Dispose()End If
(A)を下記のように変えますと、エラーでます。
Where C(0) & " And " & C(1) & " And " & C(2)
エラー:Option Strict On で 'String' から 'Long' への暗黙的な変換はできません。ここまでが、うまくいっていないコードです(AND検索(1) & AND検索(2))
以降は、一応うまくいっている、OR検索のコードです:
'SQL認証接続
Dim St As String
Dim Con As New System.Data.SqlClient.SqlConnection
Dim sql As System.Data.SqlClient.SqlCommand
Dim ServerName As String = "*****" 'サーバー名(またはIPアドレス)
Dim UserID As String = "*****" 'ユーザーID
Dim Password As String = "*****" 'パスワード
Dim DatabaseName As String = "*****"
St = "Server=" & ServerName & ";"
St &= "User ID=" & UserID & ";"
St &= "Password=" & Password & ";"
St &= "Initial Catalog=" & DatabaseName
Con.ConnectionString = St
sql = Con.CreateCommand
Con.Open()
Dim adapter = New SqlClient.SqlDataAdapter()
Dim dsCombo = New DataSet
Dim dtCombo As New DataTable'Try
If RB_OR.Checked = True Then ’OR検索
sql.CommandText = "SELECT Client_ID, ClientCode, CustomerType, VenderType, Area_ID, Staff_ID, Country_ID, ShortName, KanaCode, CompanyName, ZipCode, " _
& "Address1, Address2, Tel_in, E_mail, ClientStaffName, ClientStaffKana, Memo, Goods FROM T_M_Client " _
& "Where CustomerType= @CustomerType or VenderType= @VenderType or ClientCode= @ClientCode or KanaCode Like @KanaCode or Country_ID= @Country_ID " _
& "or Area_ID= @Area_ID or Staff_ID= @Staff_ID or ShortName Like @ShortName or CompanyName Like @CompanyName or ZipCode Like @ZipCode " _
& "or Address1 Like @Address1 or Address2 Like @Address2 or Tel_in= @Tel_in or E_mail Like @E_mail or ClientStaffName Like @ClientStaffName " _
& "or ClientStaffKana Like @ClientStaffKana or Memo Like @Memo or Goods Like @Goods or Client_ID=0 " _
& "ORDER BY T_M_Client.Client_ID"
sql.CommandType = CommandType.TextIf Me.CB_CustomerType.Text = "" Or Me.CB_CustomerType.Text Is Nothing Then
sql.Parameters.AddWithValue("@CustomerType", 999999) ’選択していないときは、明らかに偽となるようにしておく。
Else
sql.Parameters.AddWithValue("@CustomerType", Me.CB_CustomerType.SelectedValue) ’選択したときは、実際の値
End If
-----省略
adapter.SelectCommand = sql
adapter.Fill(dsCombo)
dtCombo = dsCombo.Tables(0)'▼値の表示
DataGridView1.DataSource = dtCombo'▼後処理
dtCombo.Dispose()
adapter.Dispose()
sql.Dispose()
Con.Dispose()'Catch ex As Exception
'End TryEnd Sub
回答
-
>>sql.Parameters.AddWithValue("@VenderType", True)
と書かれてますけど、これでは「VenderType = True」と識別されてしまいます。
Dim sb As New System.Text.StringBuilder If RB_AND.Checked = True Then 'AND検索 sb.Append("SELECT Client_ID") sb.Append(" , ClientCode") sb.Append(" , CustomerType") sb.Append(" , VenderType") sb.Append(" , Area_ID") sb.Append(" , Staff_ID") sb.Append(" , Country_ID") sb.Append(" , ShortName") sb.Append(" , KanaCode") sb.Append(" , CompanyName") sb.Append(" , Address1") sb.Append(" , Address2") sb.Append(" , Tel_in") sb.Append(" , E_mail") sb.Append(" , ClientStaffName") sb.Append(" , ClientStaffKana") sb.Append(" , Memo") sb.Append(" , Goods") sb.Append(" FROM T_M_Client") If Not String.IsNullOrEmpty(Me.CB_CustomerType.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("CustomerType = @CustomerType") sql.Parameters.AddWithValue("@CustomerType", Me.CB_CustomerType.SelectedValue) End If If Not String.IsNullOrEmpty(Me.CB_VenderType.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("VenderType = @VenderType") sql.Parameters.AddWithValue("@VenderType", Me.CB_VenderType.SelectedValue) End If If Not String.IsNullOrEmpty(Me.TX_ClientCode.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("ClientCode = @ClientCode") sql.Parameters.AddWithValue("@ClientCode", Me.TX_ClientCode.Text) End If If Not String.IsNullOrEmpty(Me.TX_KanaCode.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("KanaCode = @KanaCode") sql.Parameters.AddWithValue("@KanaCode", Me.TX_KanaCode.Text) End If sb.Append(" ORDER BY") sb.Append(" Client_ID") End If sql.CommandText = sb.ToString(); adapter.SelectCommand = sql adapter.Fill(dsCombo) dtCombo = dsCombo.Tables(0) '▼値の表示 DataGridView1.DataSource = dtCombo '▼後処理 dtCombo.Dispose() adapter.Dispose() sql.Dispose() Con.Dispose()
未検証ですけどこんな感じかと・・・
※If文の中の「adapter.SelectCommand = sql」以降の部分って共通ですよね?If文の外に出した方が良くないですか?
- 回答としてマーク yksaila 2012年8月4日 3:52
-
aviator_さんへ
うまくいきました! ありがとうございます。
こんな方法があるとは知りませんでした。 すばらしい! 改めて、自分の知識不足を認識し、かつ謙虚な思いになりました。
この方式で、OR条件も書き直しました(私のものは、努力は買えますが、いかにも子供っぽいですね)。
なお、本質的なことではないのですが、後日ここを訪問される方のために、ミスプリを訂正しておきます。
sql.CommandText = sb.ToString(); → sql.CommandText = sb.ToString()---- セミコロンを除きます。
sb.Append("KanaCode = @KanaCode") → sb.Append("KanaCode Like @KanaCode") ---「=」を「Like」にします。
sql.Parameters.AddWithValue("@KanaCode", Me.TX_KanaCode.Text) → sql.Parameters.AddWithValue("@KanaCode", "%" & Me.TX_KanaCode.Text & "%")
(最後の二行は、使用上の問題です。 名前を正確に入力しないと検索出来ないのは不都合なので、部分が合っていたら検索するようにしています。)
Dim sb As New System.Text.StringBuilder/ sb.Append---これは、初めて見るものでした。 非常に勉強になりました。知識が増えてくると、プログラム作成も面白くなってきます。
今後も、よろしく、ご指導お願いします。
YKsaila
すべての返信
-
どちらかというとSQL文の問題かなと。こういう時は有効フラグを使います。
... AND ClientCode= @ClientCode AND ...
とあったら
... AND (ClientCode= @ClientCode OR @ClientCodeDisabled) AND ...
とします。@ClientCodeDisabled = TRUE なら @ClientCode の如何にかかわらず TRUE になります。
別案としては動的にSQL文を生成します。WHERE句に必要なだけの検索条件を組み立てて、必要なパラメーターだけ渡します。ミスりやすいので前者の方がおすすめです。
-
>>sql.Parameters.AddWithValue("@VenderType", True)
と書かれてますけど、これでは「VenderType = True」と識別されてしまいます。
Dim sb As New System.Text.StringBuilder If RB_AND.Checked = True Then 'AND検索 sb.Append("SELECT Client_ID") sb.Append(" , ClientCode") sb.Append(" , CustomerType") sb.Append(" , VenderType") sb.Append(" , Area_ID") sb.Append(" , Staff_ID") sb.Append(" , Country_ID") sb.Append(" , ShortName") sb.Append(" , KanaCode") sb.Append(" , CompanyName") sb.Append(" , Address1") sb.Append(" , Address2") sb.Append(" , Tel_in") sb.Append(" , E_mail") sb.Append(" , ClientStaffName") sb.Append(" , ClientStaffKana") sb.Append(" , Memo") sb.Append(" , Goods") sb.Append(" FROM T_M_Client") If Not String.IsNullOrEmpty(Me.CB_CustomerType.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("CustomerType = @CustomerType") sql.Parameters.AddWithValue("@CustomerType", Me.CB_CustomerType.SelectedValue) End If If Not String.IsNullOrEmpty(Me.CB_VenderType.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("VenderType = @VenderType") sql.Parameters.AddWithValue("@VenderType", Me.CB_VenderType.SelectedValue) End If If Not String.IsNullOrEmpty(Me.TX_ClientCode.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("ClientCode = @ClientCode") sql.Parameters.AddWithValue("@ClientCode", Me.TX_ClientCode.Text) End If If Not String.IsNullOrEmpty(Me.TX_KanaCode.Text) Then If sql.Parameters.Count = 0 Then sb.Append(" WHERE ") Else sb.Append(" AND ") End If sb.Append("KanaCode = @KanaCode") sql.Parameters.AddWithValue("@KanaCode", Me.TX_KanaCode.Text) End If sb.Append(" ORDER BY") sb.Append(" Client_ID") End If sql.CommandText = sb.ToString(); adapter.SelectCommand = sql adapter.Fill(dsCombo) dtCombo = dsCombo.Tables(0) '▼値の表示 DataGridView1.DataSource = dtCombo '▼後処理 dtCombo.Dispose() adapter.Dispose() sql.Dispose() Con.Dispose()
未検証ですけどこんな感じかと・・・
※If文の中の「adapter.SelectCommand = sql」以降の部分って共通ですよね?If文の外に出した方が良くないですか?
- 回答としてマーク yksaila 2012年8月4日 3:52
-
yksaila さま
(A) "Where C(0) and C(1) and C(2) "
> 変数 C(n) には置換されません
(A)' "Where C(0) & " And " & C(1) & " And " & C(2)
> 変数 C(n) には置換されます。
ただし、置換後の左右辺のデータ型の問題でしょう。
'String' から 'Long' への暗黙的な変換 とありますから ... 。デバッグしてますか? ウォッチで変数にポインタを合わせると確認できるはずですが。
もうそろそろ、フォーラムでデバッグを頼むのはやめませんか。
- 編集済み ShiroYuki_Mot 2012年8月3日 6:35 語句訂正
-
佐祐理さんへ
ご指摘、ありがとうございます。 ただ、うまくいきません。 以下に、やったことを書きます。
1.(CustomerType=@CustomerType or @CustomerTypeDisabled)だと、エラーがでましたので下記の通りにしました。 @CustomerTypeDisabledの前に「=」を入れました。
Where (CustomerType=@CustomerType or CustomerType=@CustomerTypeDisabled) and (VenderType= @VenderType or VenderType=@VenderTypeDisabled)
2.次に下記のエラーコメントがでましたので、下記の通りにしました。 If 直下のときと Else以下のときの両方を設定しないと、エラー表示がでました。
エラー:変数 '@CustomerTypeDisabled' を宣言する必要があります。
エラー:変数 '@CustomerType' を宣言する必要があります。注;True=1(または-1)、False=0 で、サーバーは受け取っています。 一方、コンボの内容で、0=なし・1=通常 となっています。
If Me.CB_CustomerType.Text = "" OrElse Me.CB_CustomerType.Text Is Nothing Then
sql.Parameters.AddWithValue("@CustomerType", 9999) 'ここをFalseにすると、0を拾うので不可! あり得ない条件(9999)にしておく。
sql.Parameters.AddWithValue("@CustomerTypeDisabled", True)
Else
sql.Parameters.AddWithValue("@CustomerType", Me.CB_CustomerType.SelectedValue)
sql.Parameters.AddWithValue("@CustomerTypeDisabled", 9999) 'ここをFalseにすると、0を拾うので不可! あり得ない条件(9999)にしておく。
End If
If Me.CB_VenderType.Text = "" OrElse Me.CB_VenderType.Text Is Nothing Then
sql.Parameters.AddWithValue("@VenderType", 9999) 'ここをFalseにすると、0を拾うので不可! あり得ない条件(9999)にしておく。
sql.Parameters.AddWithValue("@VenderTypeDisabled", True)
Else
sql.Parameters.AddWithValue("@VenderType", Me.CB_VenderType.SelectedValue)
sql.Parameters.AddWithValue("@VenderTypeDisabled", 9999) 'ここをFalseにすると、0を拾うので不可! あり得ない条件(9999)にしておく。
End If3.CB_CustomerTypeを選択(例:2---催事)、CB_VenderTypeは空白にして検索してみます。目的はCB_CustomerTypeのみでの検索のはずです。
ところが、CB_CustomerType=2(催事)および CB_VenderType=1(通常)も加えて検索します。つまり、AND検索になっていません。
CB_VenderType.Textが空白の場合は、sql.Parameters.AddWithValue("@VenderTypeDisabled", True)です。ということは、VenderType=@VenderTypeDisabled,
つまり、VenderType=True →VenderType=1 の条件付加になるわけです。
注;True=1(または-1)、False=0 で、サーバーは受け取っていますから。一方、コンボの内容で、0=なし・1=通常 となっています。というわけで、行き詰っています。
YKsaila
-
aviator_さんへ
ご回答、ありがとうございます。 当分、質問はなくても大丈夫だろうと安心していたのに、またまた質問となってしまいました。
>>sql.Parameters.AddWithValue("@VenderType", True) と書かれてますけど、これでは「VenderType = True」と識別されてしまいます。
おっしゃる通りです、分かっていたのですが苦し紛れでやってみたのです。
>※If文の中の「adapter.SelectCommand = sql」以降の部分って共通ですよね?If文の外に出した方が良くないですか?
これも、おっしゃる通りです。 うっかりしていました。 難しくなってくる(分からなくなってくる)と、こういうのがおろそかになります。
内容については、後日勉強して、ご返事いたします。 今日(14日)、明日(15日)は私用で時間がとれませんので。
うまくいきそうな気がしています。 初めてのコードなので勉強になります。
YKsaila
- 編集済み yksaila 2012年8月3日 14:38
-
ShiroYuki_Motさんへ
ご指摘、ありがとうございます。
>(A) "Where C(0) and C(1) and C(2) " > 変数 C(n) には置換されません
これは、理解しています。 デバッグは、していますので。 コードは、これを認識していないですよね。 分かっていて、書いています。
>(A)' "Where C(0) & " And " & C(1) & " And " & C(2) > 変数 C(n) には置換されます。 ただし、置換後の左右辺のデータ型の問題でしょう。 'String' から 'Long' への暗黙的>な変換 とありますから ... 。
'String' から 'Long' への暗黙な変換 とあります ... 。 → これへの対処が分からないので質問したのです。 デバッグを頼むような”ずうずうしい”ことは、考えていません。
内容について:
C(0)="1=1" → C(0)は、String、右辺は式(これが、なぜLong?)。 C(0)がStringなのがおかしいのは分かります、ただどう変えれば良いか? これが出来れば一番簡単なのです。 directcastを使ってもうまくいかず拒否されました。 書き方が悪かったのでしょうか?
デバッグについての私見:
デバッグの能力とその人のプログラム作成能力は比例するのでしょうから、私の力不足なのは確かです。
ただ、デバッグすれば、すべて解決するものでもないと考えますが? デバッグだけで済むのなら、世の中のソフト作成は全て簡単になるのでは?
YKsaila
- 編集済み yksaila 2012年8月3日 14:36
-
yksaila さま
Function : System.Convert.ToInt64(String) As Long (戻り値は 64-bit signed integer) で変換できますが ... そういうことですか?
取り敢えず、回避は可能でしょうが、それは答えではないのでしょう?クエリの中に ID 類が色々出てきますが、どれかが Long(Int64) でデータベースに格納されていませんか?
IDE の Editer で変数上を MouseHover すると型が表示されるので、これで調べるのも手です。
なお、ご存知とは思いますが Integer は INT32 です。
ただ、変だなぁと思うのは、AND検索とOR検索とで項目の違いはないでしょうから、片方で出て他方は出ないというのが疑問です。
- 編集済み ShiroYuki_Mot 2012年8月3日 15:13 1行挿入
-
ShiroYuki_Motoさんへ
いろいろやってみた結果です:
Where以下の条件式を一個でやってみます(実験)。
1)Where C(0) --C(0)は一個でもエラーです。
2)C(0)のところに、C(0)の内容を実際に書きます。 つまり、CustomerType=" & CID &" とすると、この条件で正常に検索します。
(dim CID as integer=Cint(Me.CB_CustomerType.SelectedValue))
C(0)を論理式(?)に変換できないのなら、この方法では無理、ということになりますか?
ご指摘のやり方では、やはりC(0)を変換できなかったのですが(あるいは、私のやり方が拙い)?
なお、(2)でうまくいっているわけですから、ID類の中にLongはないということになります。
String→Long変換不可のエラーコメントが出るということは、C(0) に原因があるということでしょう。8/6記:私の以前の試行に問題があって、ここの記事は大きく書き換えました! AND条件で試行すべきところを、うっかりOR条件でやったので、エラーがでなかったのです。
YKsaila
- 編集済み yksaila 2012年8月6日 14:27
-
aviator_さんへ
うまくいきました! ありがとうございます。
こんな方法があるとは知りませんでした。 すばらしい! 改めて、自分の知識不足を認識し、かつ謙虚な思いになりました。
この方式で、OR条件も書き直しました(私のものは、努力は買えますが、いかにも子供っぽいですね)。
なお、本質的なことではないのですが、後日ここを訪問される方のために、ミスプリを訂正しておきます。
sql.CommandText = sb.ToString(); → sql.CommandText = sb.ToString()---- セミコロンを除きます。
sb.Append("KanaCode = @KanaCode") → sb.Append("KanaCode Like @KanaCode") ---「=」を「Like」にします。
sql.Parameters.AddWithValue("@KanaCode", Me.TX_KanaCode.Text) → sql.Parameters.AddWithValue("@KanaCode", "%" & Me.TX_KanaCode.Text & "%")
(最後の二行は、使用上の問題です。 名前を正確に入力しないと検索出来ないのは不都合なので、部分が合っていたら検索するようにしています。)
Dim sb As New System.Text.StringBuilder/ sb.Append---これは、初めて見るものでした。 非常に勉強になりました。知識が増えてくると、プログラム作成も面白くなってきます。
今後も、よろしく、ご指導お願いします。
YKsaila
-
yksaila さま
解決なされたようなので、ご参考まで。
クエリを文字列で与える、いわゆるアドホッククエリの落とし穴です。
置換される文字は元のデータベースにどのような型で入っていようと文字で指定しなければなりません。
文字なら Where CODE_NAME = 'ThisIsCode'
数値なら Where CODE_ID = 123
この場合、右辺を変数で与えるなら valueName = "'ThisIsCode'"、value_ID ="123"
です。
CID = DirectCast(Me.CB_CustomerType.SelectedValue, Integer)
C(0) = "CustomerType= " & CID & "" ’選択したときの、実際の値
とされたため、左辺は文字列、右辺は不定(つまりエラー)となり、CID のデ-タベース上での定義は INT64(Long) だったのではないでしょうか?aviator_ さまが StringBuilder を使って示された、パラメータ化されたクエリでは、型を厳密に定義するため、このようなトラブルを回避し易くなります。
Hoshina さまが書かれた様に不要な条件式は省いた方が高速化されますので、StringBuilder で Append する時に、画面上の指定を取り込み、不要な条件式を省くロジックを組み込まれることをお勧めします。難しいかな?
なお、文字列の連結時には毎回新たなメモリ領域が割り当てられるため、高速化のために StringBuilder Class を使うと良い とあります。
-
ただ、デバッグすれば、すべて解決するものでもないと考えますが? デバッグだけで済むのなら、世の中のソフト作成は全て簡単になるのでは?
できれば、この言葉の意図を説明願いたい。
プログラムは、書いてあるとおりに動作します。人は、「こうなって欲しい」と思ってコードを書きますが、様々な要因によって「書きたいこと」と「書いてあること」にずれが生じます。このずれによって期待しない動作をすることを「バグ」と呼びます。この「バグ」を取ることを「デバッグ」といいます。
従って、バグがあるならデバッグをしなければならないと考えます。デバッグをせずに、どうやってバグを取ろうとおっしゃるのでしょうか。もちろん、バグがなければデバッグの必要はありません。よって、この言葉が「バグのないプログラムを書こう」という意図であるなら、賛成します。実現性については置いておくとして。
Jitta@わんくま同盟
-
Jittaさんへ
うーん、説明が難しいですね。
私に限って言えば:デバッグだけでは解決しない、ということは以下のようなことです。
1.知識不足
2.発想の転換---
Hoshinaさんの忠告を例にあげます:「選択しないとき真にしたい → 選択しないときは,WHERE にその項目を指定しない → 選択したときだけ,WHERE にその条件を指定する」
私は、回答に記載したような方法を知らなかったので、上記のような発想をしませんでした。 もし、していたら、この方法を調べたかもしれません(ま、無理だったでしょうが)?
このような発想をしなかったこと、Hoshinaさんの意図をすぐに理解できなかったことに、私自身驚きました。
これは、私のデバッグが問題なのではなく、 知識不足、発想の不足が原因です。 どれだけ、豊かな発想が出来るかは、その人の経験・能力によるのでしょう。つまり、どれだけ引き出しをもっているか、ですね。 これについては、限界は無いわけですから、むしろ、このほうが重要なことだと私は思ったわけです。
YKsaila
- 編集済み yksaila 2012年8月6日 14:48
-
Shiroyuki_Motoさんへ
Where C(0)---、と出来ればひとつ引き出しが増えるのですが。 だめですね、この方式は、現時点では、うまくいきません。
1.where 以降に、C(0)一個入れても、「Cは、関数として認識されません」と、エラーがでます。
2.C(0) = "CustomerType= " & CID & "" / C(0) = "CustomerType= '" & CID & "'" -----いずれも、変化なしで、エラーです。
3.サーバー上では、CustomerTypeは”Int”です。 Int32なはずです。
YKsaila
-
yksaila さま
デバッグに関して一言!
デバッガーってとっても便利なのですよ。昔なら、引っかかった式の値を入れては表示入れては表示してプログラムを直していました。
これが、今のデバッガーでは値をトレースしていける訳ですから、使わない手はナイ!yksaila さまだって、簡単な間違いはデバッグツールを使わなくとも勘が働き、ちょちょいと直せるでしょう。
自分でデバッグした経験は必ず次に役立ちます。
その為にも、デバッグには慣れておかれるようお勧めします。
せっかく Microsoft が長年の年月を掛けた便利なツールなのですから、使ったほうが得ですよ。それと、私が使っているのは VB2008SP1ExpressEdition なのですが、ヘルプの中に「コミュニティ リソース : 他の開発者から助けを得る」
http://msdn.microsoft.com/ja-jp/library/ms233949(v=VS.90).aspx
(LocalHelp on VB2008EE SP1)
という項目があります。
だれかがデバッグしてくれることを期待しないでください。と表記されています。yksaila さまの VB の知識をこのフォーラムでの投稿から推し量るに、もう十分上の行に当てはまるレベルにあるのでは、と考えました。
苦言かも知れませんが、皆、通る道です。
デバッガーを使いこなしましょう。それと、私の説明をよく読まれましたか?
CID > CID.toString
でどうですか?
それと、これは、悪い例です。今回のデバッグが終わったら2度とこのような書き方はしないで下さい。
理由は直前の投稿を参照。 -
私は、回答に記載したような方法を知らなかったので、上記のような発想をしませんでした。 もし、していたら、この方法を調べたかもしれません(ま、無理だったでしょうが)?
なるほど、了解しました。確かに、デバッグだけではないですね、ありがとうございます。
私は、すべてのことは関連があると考えています。あるいは、すべてのことは、その事象以外の事象を暗喩していると考えています。このことから、似た事例を探します。そして、同じように適用できないか、考えます。たとえば、ガリレオは、木星を観測して4つの衛星を発見しました。衛星が木星の周りを回るさまを観測し、地球も同じように太陽の周りを回っているのではないかと考えました。このように、似た事例を探し、適用できないか考えます。
経験を手っ取り早く増やす方法はないと思いますが、他人の経験を学ぶ方法は多々あります。その一つが掲示板、つまりここです。私は、答えるために見ているのではありません。自分がいつか参考にするかもしれないおもしろい事象を見るために、ここを見ています。そして、興味を持ったものに対して試すなどのことをして、回答できるなら回答します。また、他の回答者の回答を読むことで、その方の経験を学んでいます。
Jitta@わんくま同盟
-
-
yksaila さま
あまり上手に説明できないんですが、
sql.CommandText は Text (文字列)で与えます。
基本は
文字なら Where CODE_NAME = 'ThisIsCode'
数値なら Where CODE_ID = 123
この場合、右辺を変数で与えるなら valueName = "'ThisIsCode'"、value_ID ="123"
です。
この中に C(0) とか CID とかの文字列が含まれる場合、クエリの実行時点で、変数や関数と解釈されその値に置換実行されます。
それ故、" CustomerType= CID " ではOK
C(0) では Function C があるものと解釈されます。さて、CID = DirectCast(Me.CB_CustomerType.SelectedValue, Integer)
C(0) = "CustomerType= " & CID & ""
の場合の右辺で、何か気づきませんか?
"CustomerType= " は文字列、CID はInteger、この二つを連結できますか?
C(0) = "CustomerType= " & CID.ToString & ""
これで、どうでしょうか?なお、このようなクエリをアドホックと呼び、知識のみとし実際には利用しないことをお勧めします。
なおなお、long のエラーメッセージは、試行錯誤の途中で CID 以外の DB 列 の中に Int64 の設定のものがあってそれが表示されたとしか想像できません。
一旦、DB の列定義を精査することをお勧めします。 -
Shiroyuki_Motoさんへ
出来ました。 Where C(0); をデバッグで調べると、C(0)は、String型。 これがいけないのだと、考えました。
それで、Where C(0) → Where " & C(0) & " としました。 これで、やっとC(0)を認識したようです、うまく動きます。 " & & "で、くくらないとダメなのですね。 意外でした!
二個の連結も下記コードで成功していますので、これで全てOKとなるでしょう。
いろいろ、ありがとうございました。 今後も、よろしく、お願いします。
YKsaila
以下、参考コード:
Dim C(20) As String
Dim CID, VID As Integer
If Me.CB_CustomerType.Text = "" OrElse Me.CB_CustomerType.Text Is Nothing Then
C(0) = "1 = 1"
Else
CID = CInt(Me.CB_CustomerType.SelectedValue)
C(0) = "CustomerType= " & CID & ""
End IfIf Me.CB_VenderType.Text = "" OrElse Me.CB_VenderType.Text Is Nothing Then
C(1) = "1=1"
Else
VID = CInt(Me.CB_VenderType.SelectedValue)
C(1) = "VenderType= " & VID & ""
End Ifsql.CommandText = "SELECT Client_ID, ClientCode, CustomerType, VenderType, Area_ID, Staff_ID, Country_ID, ShortName, _
& KanaCode, CompanyName, ZipCode, " _
& "Address1, Address2, Tel_in, E_mail, ClientStaffName, ClientStaffKana, Memo, Goods FROM T_M_Client " _
& "Where " & C(0) & " AND " & C(1) & " " ’ここが間違えやすいですね。
- 編集済み yksaila 2012年8月7日 4:19
-
yksaila さま
解決済みの件に蛇足となるかも知れませんが、文字列連結用の簡単なプログラムを書いてみました。
私も知識不足で上手に説明できなかったので。お暇な折に是非以下のサイトからソースをコピーして戴いて、遊びのつもりでコードを弄って見て下さい。
似たようなエラーメッセージが出たり、Option Strict On/OFF の設定でコンパイラーの挙動がどう変わるかが分かると思います。http://shiroyuki-mot-says.blogspot.com/2012/08/vb-prg-joint.html (2012/08/09公開予定)
宜しければ、ついでに、コメントもお願いします。
-
それで、Where C(0) → Where " & C(0) & " としました。 これで、やっとC(0)を認識したようです、うまく動きます。 " & & "で、くくらないとダメなのですね。 意外でした!
意外でしたで済まさずに、自身のコードが何故NGなのかを明確に認識して下さい。
そうしていただかないと次に繋がらないです。
>意外でしたで済まさずに、自身のコードが何故NGなのかを明確に認識して下さい。
ご忠告、ありがとうございます。 でも、”意外でした” に、強い意味はありませんので、誤解しないでください。 常に、なぜ? 根拠は? と問う習慣は、身につけているつもりです。
なぜ、こんなことに早く気付かなかったんだろう !---- という後悔・反省の意味で使いました。
Where C(0) だとコードは、C(0)を文字通りC(0)としか認識しない、考えてみたら当然です。 コードからすれば、なんのことか理解できない、だからエラー表示となる。 C(0) = "CustomerType= " & CID & "" と前に書いても、Where以降のC(0) には、それは伝わらない、私が勝手にそう思い込んでいるだけ! つまり、Where 以降のC(0) に、C(0)が実はCustomerType= " & CID & " を表していることを伝えなければならない。 この働きが、" & C(0) & " なのでしょう。 専門的な用語はうまく使えませんが、要するにそういうことだと思います。 これは、修正時に認識しました。
デバッグした時に、このエラー表示の意味がしっかり捉えられていたら、違っていたかもしれません。
YKsaila
- 編集済み yksaila 2012年8月9日 3:25
-
このフォーラムがなかったら、ここまででさえ辿りつけなかったです。 入口で迷い続け、きっと諦めていたでしょう。 こういう意味では、ネットは非常にありがたいです。
私がプログラミングを始めたのは1981年です。この頃、日本にはインターネットもパソコン通信もありませんでした。もちろん、身近にプログラミングについて詳しい人はいません。まぁ、その頃と今とでは、憶えることの量が違いますけど。
まずは、本です。自分がそれで憶えてきたから言うのではありません。本には余白があります。ここに書き込めるというのが、ネットに対する強みです。且つ、英語や漢字を覚えるときには声に出して読みながら書くのが良いといわれますが、これは目、手、口、耳と4つの感覚を刺激するからです。同じ事がプログラミングにもいえ、コードをコピペするのではなく自分で書くことで、使用する感覚を増やせます。また、ネット聞くときには、今見えている問題だけを尋ねます。しかし、本は体系的に書かれています。学ぶためには、体系的に学ぶことが大切です。
ネットがなくても学ぶことはできます。最初は、ネット以外から学ぶことを勧めます。
Jitta@わんくま同盟
-
私がプログラミングを始めたのは1981年です。この頃、日本にはインターネットもパソコン通信もありませんでした。もちろん、身近にプログラミングについて詳しい人はいません。まぁ、その頃と今とでは、憶えることの量が違いますけど。
まずは、本です。自分がそれで憶えてきたから言うのではありません。本には余白があります。ここに書き込めるというのが、ネットに対する強みです。且つ、英語や漢字を覚えるときには声に出して読みながら書くのが良いといわれますが、これは目、手、口、耳と4つの感覚を刺激するからです。同じ事がプログラミングにもいえ、コードをコピペするのではなく自分で書くことで、使用する感覚を増やせます。また、ネット聞くときには、今見えている問題だけを尋ねます。しかし、本は体系的に書かれています。学ぶためには、体系的に学ぶことが大切です。
ネットがなくても学ぶことはできます。最初は、ネット以外から学ぶことを勧めます。
Jitta@わんくま同盟
Jittaさんへ
おっしゃる通りだと思います。 2,3冊買ったのですが、あまり良くないようで使っていません(導入的なことは書いてありますが、肝心なところの記入がない?)。 私も、良い本はぜひ欲しいです!
良い本がありましたら、紹介していただけますか?
YKsaila
- 編集済み yksaila 2012年9月4日 7:55
-
Jittaさんへ
おっしゃる通りだと思います。 2,3冊買ったのですが、あまり良くないようで使っていません(導入的なことは書いてありますが、肝心なところの記入がない?)。 私も、良い本はぜひ欲しいです!
良い本がありましたら、紹介していただけますか?
YKsaila
人それぞれ、経験によって、“良い本”というのは異なると思っています。同じ人でも、1年目と3年目では、同じ本でも感じることが違うと思います。
とりあえず、amazon 等で、評判の良い本を調べ、それを本屋で探して立ち読みしてはいかがでしょうか。。。ということを、「本を紹介してください」といわれる度に繰り返しています。膨大な量から見つけるのは難しい。かといって、何がわかりやすいかは個人によって違う。そこで、評判の良い本をピックアップしてみよう、ということです。
私のお勧めは、まずは MSDN ライブラリです。「開発ツールと言語ドキュメント」を、“さらっと流します”。書いてあることを“覚える”必要はありません。しかし、“何が書いてあるか”を記憶するようにします。たとえば、「技術のクイック リファレンスに、主なプロジェクトでの開発方法が載っている」の様なことを覚えます。すると、「どういうプロジェクトを作れば良いのだろう?」と迷ったときに、「載っているページがあった」ということを思い出せれば、探すことが出来ます。
Jitta@わんくま同盟