こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

抽出条件が複数ある場合で,抽出元のデータに未入力がある場合

Accessを利用して住所録のデータベースを作成しています。

検索用フォームのレコードソースにクエリを指定して,フォーム上にテキストボックスを2つ配置し,コマンドボタンをクリックして抽出結果をフォームに表示させます。一つめのテキストボックスには氏名,二つ目のテキストボックスには,勤務先の入力をします。以下の条件での検索結果をフォーム上に表示させたいのですが,(3)の場合に,勤務先がない(未入力の)人のデータも同時に抽出されてしまいます。

(1)氏名のみの条件で該当する人
(2)氏名及び勤務先の条件で該当する人
(3)勤務先のみの条件で該当する人
(4)条件を入力しない場合

<住所録>
ID___氏名_________フリガナ___________勤務先
1____鈴木 健一__スズキ ケンイチ__新日本商事
2____中村 主水__ナカムラ モンド___新日本商事
3____山田 太郎__ヤマダ タロウ_____


クエリには
WHERE ((([tbl THE CARD].氏名) Like "*" & [Forms]![frm_検索用]![氏名] & "*") AND (([tbl THE CARD].勤務先) Like [Forms]![frm_検索用]![勤務先] & "*")) OR ((([tbl THE CARD].氏名) Like "*" & [Forms]![frm_検索用]![氏名] & "*") AND ((([tbl THE CARD].[勤務先]) Like [Forms]![frm_検索用]![勤務先] & "*") Is Null)) OR ((([tbl THE CARD].勤務先) Like [Forms]![frm_検索用]![勤務先] & "*"))
ORDER BY [tbl THE CARD].ID;
と記載しました。

例えば,氏名と勤務先の両方の検索結果を表示させる場合,
・氏名が該当し,勤務先が空白のデータ
が抽出されます。氏名と勤務先の両方に検索条件をいれたときには,勤務先が空白のデータを抽出しないようにしたいのですが,どうしたら良いでしょうか。氏名だけで検索するときには,勤務先が空白かどうかは考慮しない結果を表示させたいと思います。

過不足があると思いますが,ご指導宜しくお願いします。

投稿日時 - 2008-05-22 11:00:22

QNo.4041150

困ってます

質問者が選んだベストアンサー

横レス失礼致します。

No.1の方の組み方では、検索条件とするフィールドを追加するほど、複雑になっていきます。
VBAで対応されるのでしたら、以下のようにした方が、簡単にフィールドの追加ができます:


Private Sub 表示_Click()
On Error Goto エラー処理

  Dim StrWhr As String   'Where条件式
  Dim StrMsg As String   '表示メッセージ
  Dim StrSrc As String   'レコードソース
  Dim stDocName As String   '表示用フォームの名前

  '検索条件が指定されているもののみを、Andで順次連結してWhere条件式を作成
  If Nz(Me!氏名, "") <> "" Then
    StrWhr = "氏名 Like '*" & Me!氏名 & "*'"
  End If
  If Nz(Me!勤務先, "") <> "" Then
    StrWhr = IIF(StrWhr = "", "", StrWhr & " And ") & "勤務先 Like '*" & Me!勤務先 & "*'"
  End If
  If Nz(Me!住所, "") <> "" Then
    StrWhr = IIF(StrWhr = "", "", StrWhr & " And ") & "住所 Like '*" & Me!住所 & "*'"
  End If
  '以降、検索条件を入力するテキストボックスごとに、以下のセットで追加すればOKです。
  'If Nz(Me!○○, "") <> "" Then
  '  '曖昧検索の場合
  '  StrWhr = IIF(StrWhr="", "", StrWhr & " And ") & "○○ Like '*" & Me!○○ & "*'"
  '  '完全一致検索(数値型)の場合
  '  'StrWhr = IIF(StrWhr="", "", StrWhr & " And ") & "○○ = " & Me!○○
  'End If

  '↓~~~OpenFormのWhere条件で絞り込みをする場合、ここの一団は不要~~~↓
  If StrWhr="" Then
    StrSrc = "Select * From [tbl THE CARD] Order By ID;"
  Else
    StrSrc = "Select * From [tbl THE CARD] Where " & StrWhr & " Order By ID;"
  End If
  '↑~~~OpenFormのWhere条件で絞り込みをする場合、ここの一団は不要~~~↑

  '確認メッセージで「OK」を選択したら、絞り込み(または解除)を実行
  If MsgBox(StrMsg, vbOKCancel, "確認") = vbOK Then
    'レコードソースの切替で対応する場合
    '(フォーム側のレコードソースは空白にしておくと、コントロールに一瞬エラーが表示
    ' されるものの、表示は速くなります)
    DoCmd.OpenForm stDocName
    Forms(stDocName).RecordSource = StrSrc
    'フィルタ条件で対応する場合(一旦レコードを読み込んでからの絞り込みになる分、
    ' 表示は遅くなります)
    'DoCmd.OpenForm stDocName, , , StrWhr
  End If

終了処理:
  Exit Sub
エラー処理:
  MsgBox Err & Error$, , Me.Name & " 表示"
  Resume 終了処理
End Sub


・・・以上です。

投稿日時 - 2008-05-22 23:08:15

補足

詳細な構文を書いていただき,ありがとうございます。とりあえず,単純化したDBを作成し,下記のとおり記載してコマンドボタンをクリックしてみましたが,目的のフォームは表示されるものの,データが全て「#Name?」と表示されてしまい,レコードを抽出することができません。ここでは,タイトルを検索することにしています。どこが間違っているのでしょうか?VBAを使うのは初めてなので,参考書を見てみましたが,理解できません。宜しくお願いします。

Private Sub コマンド28_Click()

Dim StrWhr As String 'Where条件式
Dim StrMsg As String '表示メッセージ
Dim StrSrc As String 'レコードソース
Dim stDocName As String '表示用フォームの名前

'検索条件が指定されているもののみを、Andで順次連結してWhere条件式を作成
If Nz(Me!タイトル, "") <> "" Then
StrWhr = "タイトル Like '*" & Me!タイトル & "*'"
End If

'以降、検索条件を入力するテキストボックスごとに、以下のセットで追加すればOKです。
'If Nz(Me!○○, "") <> "" Then
'  '曖昧検索の場合
'  StrWhr = IIF(StrWhr="", "", StrWhr & " And ") & "○○ Like '*" & Me!○○ & "*'"
'  '完全一致検索(数値型)の場合
'  'StrWhr = IIF(StrWhr="", "", StrWhr & " And ") & "○○ = " & Me!○○
'End If

If MsgBox(StrMsg, vbOKCancel, "確認") = vbOK Then
'レコードソースの切替で対応する場合
'(フォーム側のレコードソースは空白にしておくと、コントロールに一瞬エラーが表示
' されるものの、表示は速くなります)
DoCmd.OpenForm "F入力フォーム のコピー", acNormal

Forms("F入力フォーム のコピー").RecordSource = StrSrc
'フィルタ条件で対応する場合(一旦レコードを読み込んでからの絞り込みになる分、
' 表示は遅くなります)
'DoCmd.OpenForm "F入力フォーム のコピー"stDocName, , , StrWhr
End If

End Sub

投稿日時 - 2008-05-23 12:52:12

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.5

No.2~4です。

> コマンドボタンは何の反応も示しませんでした。

If文で「Else」の後に「ElseIf」をおくと、エラーになるはずです。
ですので、コマンドボタンが反応しなくなったのは、そのエラーのためではないかと思います。
(VBAでのエラー処理の記述によって、エラーメッセージを出さずに処理を終了させることも
 可能なので、恐らくそういった処理がされているものと考えられます)


> 両方を使用したい場合

ご要望の動作が
 1)フィルタ適用時は、そのフィルタを反映してレポートを展開
 2)(フィルタは適用しておらず、)引数OpenArgsで式が渡されている場合は、その式を反映
  してレポートを展開
 3)フィルタを適用しておらず、OpenArgsによる式の指定もない場合は、絞り込みをせずに
  レポートを展開
ということでしたら、以下のようになります:

Private Sub ラベル自宅_Click()

Dim stDocName As String

stDocName = "rpt_ラベル自宅"
If Me.FilterOn Then              'フィルタ適用時(=「1」相当)
  DoCmd.OpenReport stDocName, acViewPreview, , Me.Filter
ElseIf Nz(Me.OpenArgs, "")="" Then   'フィルタ非適用・OpenArgs不使用(=「3」相当)
  DoCmd.OpenReport stDocName, acViewPreview
Else                        'フィルタ非適用・OpenArgs使用時(=「2」相当)
  DoCmd.OpenReport stDocName, acViewPreview, , Me.OpenArgs
End If
End Sub


・・・以上です。

但し、もしも「4)引数OpenArgsで式を渡した上で、表示用フォームを右クリックするなどして
フィルタによる絞り込みも適用した場合」と状態があり得るとすると、上記では不充分という
ことになってしまいます。
(「Me.FilterOn」が合致することになるため、表示用フォームで行った追加絞り込みのみが
 有効になり、条件指定用のフォームで指定された検索条件(=OpenArgs)が無視される)

その場合は、上記の代わりに以下のようなコードにして下さい:

Private Sub ラベル自宅_Click()

  Dim stDocName As String
  Dim StrCnd As String

  stDocName = "rpt_ラベル自宅"

  'フィルタやOpenArgsの適用状況を元に、レポートに適用する式を作成し直します。
  '(No.2の回答で、テキストボックスの追加時に行ったのと同様の考え方です)
  StrCnd = Nz(Me.OpenArgs, "")
  If Me.FilterOn Then        'フィルタ適用(=FilterOnがTrue)時は「Me.Filter <> ""」
    StrCnd = IIF(StrCnd = "", "", StrCnd & " And ") & Me.Filter
  End If

  If StrCnd = "" Then  'フィルタもOpenArgsも適用していなかった場合
    DoCmd.OpenReport stDocName, acViewPreview
  Else            '何らかの形で絞り込みが掛けられていた場合
    DoCmd.OpenReport stDocName, acViewPreview, , StrCnd
  End If

End Sub

投稿日時 - 2008-05-29 23:32:40

お礼

数回に渡る拙い質問に丁寧に回答していただき,ありがとうございました。お陰様で満足の行くデータベースが作成できました。これからも宜しくお願いいたします。また,これを機会にVBAを少し勉強してみることにしました。

投稿日時 - 2008-06-02 09:49:18

ANo.4

No.2,3です。

> DoCmd.OpenReport stDocName, acViewPreview, , Me.Filter

表示用フォームに適用された絞り込み(フィルタ)をレポートに転用していた、ということですね。
だとすると、「レコードソース切替」ではなく「フィルタ条件使用」にするというのが一番無難では
あります。

ただ、そうすると、No.2で回答した通り、表示速度は低下します。
ですので、「レコードソース切替」という手段は保ちつつ、改修を最小限にするという観点から、
「フィルタに相当する式を表示フォームに渡しておき、レポート展開時にその式を使用する」、
というのがよいかと思います。


具体的には以下の通りです(それぞれ改修が必要になる部分のみの抜粋):

【表示用フォームを開くコマンドボタンでの改修内容】
 <現状>
  DoCmd.OpenForm stDocName
 <改修後>
  'OpenFormの引数OpenArgsとして、表示用フォームにStrWhrの値を渡します。
  DoCmd.OpenForm stDocName, , , , , , StrWhr

【表示用フォームの、レポートを開くコマンドボタンでの改修内容】
 <現状>
  If Me.FilterOn Then
    DoCmd.OpenReport stDocName, acViewPreview, , Me.Filter
  Else
    DoCmd.OpenReport stDocName, acViewPreview
  End If
 <改修後>
  '従来のFilterの代わりに、OpenArgsで受け取った式をレポートに適用します。
  '(「OpenArgs=""」(=空)は、フィルタを適用していない場合(→FilterOn=False)に相当)
  If Nz(Me.OpenArgs, "") = "" Then
    DoCmd.OpenReport stDocName, acViewPreview
  Else
    DoCmd.OpenReport stDocName, acViewPreview, , Me.OpenArgs
  End If


・・・以上です。

投稿日時 - 2008-05-23 23:02:00

補足

お返事が遅くなりました。上記の記述でできました。本当にありがとうございました。最後に,もう一つ,質問があります。表示用フォームの、レポートを開くコマンドボタンにおいて,
(1)フィルタを適用したデータをレポートに表示させる(以前に設定していた構文)
(2)フィルタに相当する式を表示フォームに渡しておき、レポート展開時にその式を使用する(今回教えていただいた構文)
の両方を使用したい場合,
Private Sub ラベル自宅_Click()
Dim stDocName As String
stDocName = "rpt_ラベル自宅"
If Nz(Me.OpenArgs, "") = "" Then
DoCmd.OpenReport stDocName, acViewPreview
Else
DoCmd.OpenReport stDocName, acViewPreview, , Me.OpenArgs

ElseIf Me.FilterOn Then
DoCmd.OpenReport stDocName, acViewPreview, , Me.Filter
Else
DoCmd.OpenReport stDocName, acViewPreview
End If
End Sub
と,単純にくっつけてみましたが,コマンドボタンは何の反応も示しませんでした。何度も,申し訳ありませんが,もし可能でしたらその方法を教えていただけると助かります。

投稿日時 - 2008-05-28 09:14:41

ANo.3

No.2です。

> データが全て「#Name?」と表示されて

これは、レコードソースが空のフォームで、テキストボックスのコントロールソースにフィールド名を
入力している場合に起こるエラーです。
(前回の回答で、「コントロールに一瞬エラーが表示される」と言ったエラーそのものになります)

補足欄に書かれたコードを見ると、レコードソースの切替で対応する方法を選択されていますが、
「↓~~~・・・~~~↓」から「↑~~~・・・~~~↑」で囲んだ『Where条件で絞り込む場合
は不要な部分』=『レコードソースの切替で対応する場合は必要な部分』が、省略されて
しまっています。

そのため、「StrSrc」(=レコードソース)にSQL文が記録されず空(="")のままになってしまっているので、
「#Name?」(=「レコードソースに、そのNameのフィールドがありませんよ?」)というエラーが表示された
ままになって(=一瞬ではなくなって)しまっているわけです。

ですので、「↓~~~・・・~~~↓」から「↑~~~・・・~~~↑」で囲んだ部分を追加すれば、
上記のエラーは解消するものと思います。



※Where条件を使用する場合とレコードソース切替の場合で、コードを完全に分けてしまった方が
 わかりやすかったかもしれません。反省(汗)

投稿日時 - 2008-05-23 14:57:13

補足

ありがとうございました。が,表示用のフォームに設定したコマンドボタンが使用できなくなってしまいました・・・・。表示用のフォームには,
Private Sub 封筒角2勤務先_Click()
Dim stDocName As String
stDocName = "rpt_封筒角2勤務先"
If Me.FilterOn Then
DoCmd.OpenReport stDocName, acViewPreview, , Me.Filter
Else
DoCmd.OpenReport stDocName, acViewPreview
End If
End Sub
という構文を書いていたのですが,検索用フォームのコマンドボタンを使用して表示用フォームに表示させたデータはフィルタ処理されていないようです。封筒角2勤務先のコマンドボタンを押すと,全件がレポートに表示されてしまいます。

(1)検索用フォームから開く表示用フォームを別個に作成し,新しいコマンドボタンを作成して,検索用フォームからの検索結果をレポートに表示させる

(2)今の表示用フォームのコマンドを書き換える

のどちらかだと思うのですが,ご教示お願いいたします。

投稿日時 - 2008-05-23 15:56:37

住所録:

ID__氏名_______フリガナ________勤務先
_1__鈴木 健一__スズキ ケンイチ__新日本商事
_2__中村 主水__ナカムラ モンド__新日本商事
_3__山田 太郎__ヤマダ タロウ______________
_4__鈴木 健二__スズキ ケンジ______________

このようなテーブルをもとに表タイプのフォームを作成します。
フッターに[参照する氏名]と[参照する勤務先]という参照したいデータの入力欄を配置。

参照する氏名__[鈴__________]
参照する勤務先[____________]

_1__鈴木 健一__スズキ ケンイチ__新日本商事
_4__鈴木 健二__スズキ ケンジ______________

参照する氏名__[鈴__________]
参照する勤務先[新__________]

_1__鈴木 健一__スズキ ケンイチ__新日本商事

で、このような検索結果を得るサンプルコードです。

Private Sub コマンド_参照_Click()
  Dim A    As Integer
  Dim strWhere As String
  
  A = Abs(Len(Me.参照する氏名 & "")) + Abs(Len(Me.参照する勤務先 & "") * 2)
  Select Case A
    Case 1
      strWhere = "氏名 LIKE '" & Me.参照する氏名 & "*'"
    Case 2
      strWhere = "勤務先 LIKE '" & Me.参照する勤務先 & "*'"
    Case 3
      strWhere = "氏名 LIKE '" & Me.参照する氏名 & "*' AND 勤務先 LIKE '" & Me.参照する勤務先 & "*'"
    Case Else
  End Select
  If Len(strWhere & "") Then
    Me.RecordSource = "SELECT * FROM 住所録 WHERE " & strWhere & " ORDER BY ID"
    Me.Requery
  End If
End Sub

ここでは4つのケースに応じて単純に WHERE節を生成しています。
滅茶苦茶に複雑なクエリに頭を悩ますよりも、やりたいことをそのまんま書く。
レコードソースを書換えてリクエリすれば事足りる訳ですから・・・。

投稿日時 - 2008-05-22 12:13:31

補足

回答ありがとうございます。氏名,勤務先の他に,IDや住所,電話番号等でも検索したい場合には,条件を加筆していけば,いくらでも増やせるのでしょうか?

コマンドボタンを押して検索結果を表示させるのは別のフォームを使いたいので,
Me.Requery
  End If
の後に
End Select
  DoCmd.OpenForm stDocName, , , "[frm THE CARD]='" & Me![氏名] & "'"
と記述しましたが,反応しません。どこが間違っているのでしょうか。
End Sub

投稿日時 - 2008-05-22 15:03:46

あなたにオススメの質問