Microsoft Access 掲示板

views
4 フォロー
6,283 件中 4,761 から 4,800 までを表示しています。
13
hiroton 2020/09/07 (月) 16:49:01 2d6b2@f966d

Mid関数もちゃんと使ってください

DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter, 6), , acNormal
'または'
DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter, Len(" AND ") + 1), , acNormal

6はマジックナンバーってやつですね。テンプレ的な記述ですが、意味のある形で記述しておくと後で見直した時も何をやっているのか分かりやすいコードになります

こういった検索なんかで複数の中からいくつかを選ぶ場合、例えば
「A and B and C」
「B and C」
「A and C」
「A」
のように、選択された項目数nに対して連結するための文字列がn-1必要という形になります。
コードを記述するなら

If (Aの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Aの条件
End If
If (Bの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Bの条件
End If
If (Cの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Cの条件
End If

のように、毎回Ifでチェックしてもいいんですが、

If (Aの条件があった場合) Then strFilter = strFilter & " AND " & Aの条件
If (Bの条件があった場合) Then strFilter = strFilter & " AND " & Bの条件
If (Cの条件があった場合) Then strFilter = strFilter & " AND " & Cの条件

If strFilter <> "" Then
  '先頭に必ずいらない" AND "がついているので取り除く'
  strFilter = Mid(strFilter, Len(" AND ") + 1)
End If

のように作りこむとコードがすっきりするというテクニックです。このテクニックを使っているので、最後にフィルター文字列を指定する部分でMid(strFilter, 6)とするわけです


ついでですが
BuildCriteria関数の2番目に指定している「10」もマジックナンバーってやつです。関数の動きを切り替えるためのいわばモード指定なんですが、ここにはデータ型を指定することとなっています
標準関数で使うこういう数値には組み込み定数というのが用意されていて、このデータ型の場合、DataTypeEnum 列挙 (DAO)が使えます

BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")
'次の記述でも同じ'
BuildCriteria("伝票NO", dbText, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

「10」だと10ってなんだよってなりますが「dbText」だと何となく意味がわかりますね。何か調べようと思った時も「dbText」なら検索のキーワードに使いやすいです

1

タブ区切りデータは、見出しなし、
追加先のテーブルとフィールドの並び順は同じとします。

フォーム上には、下記のコントロールが配置してあるとします。
テーブル名を入力するテキストボックス「txtテーブル名」
タブ区切りデータを貼り付けるテキストボックス「txtデータ」
クリックするとテーブルにデータ追加するコマンドボタン「データ追加」

Private Sub AddData(tblname As String, ByRef s As String)
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim a, i As Long, j As Long
    Dim Datas

    Set db = CurrentDb
    Set rs = db.OpenRecordset(tblname)
    a = Split(s, vbNewLine)
    For i = 0 To UBound(a)
        Datas = Split(a(i), vbTab)
        rs.AddNew
        On Error Resume Next
        For j = 0 To UBound(Datas)
            rs(j) = Datas(j)
        Next
        On Error goto 0
        rs.update
    Next
End Sub

Private Sub データ追加_Click()
    Call AddData(Me.txtテーブル名, Me.txtデータ)
End Sub

こんな感じです。

12
セロハン 2020/09/07 (月) 15:49:45 0029a@1c915

数値の左右には*の半角も入っています。(表示で消えています)

11
セロハン 2020/09/07 (月) 15:48:31 0029a@1c915 >> 10

なぜかコードが消えてしまったのでもう一度記載します。
DoCmd.OpenForm "F_案件", acNormal, "", strFilter, , acNormal

このときのstrFilterに格納された変数
⇒" AND 案件NO Like "0001" And 案件NO Like "0002""

10
セロハン 2020/09/07 (月) 15:46:05 0029a@1c915 >> 9

ありがとうございます。
おっしゃるとおり、「10」のところはお手本にしたコードの数字(6)が理解できず、
そのまま何やら勘違いして変更してしまっていました…
下記コードで実行してみたところ、絞り込み件数は0となりましたがエラーは出ませんでした。
伝票NO「0001 0002」を表示したいのですが、


strFilterに格納された変数
⇒" AND 伝票NO Like "0001" And 伝票NO Like "0002""

どこをなおせばよいのでしょうか…

6

今日は無理ですが、明日、出先にAccess2013環境があるので試してみます。

9
hiroton 2020/09/07 (月) 15:12:52 2d6b2@f966d

ちゃんと内容見てないけど
DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal

DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter,10), , acNormal

ここの「10」って数値もあんまり見ないので(正しいのかどうかわかりません)、このあたりプログラムがどう動くのかという基本を見直してみるといいと思います

8
セロハン 2020/09/07 (月) 14:50:06 0029a@1c915

上記7番にて、以前いただいた投稿に返信したのですが
新しい投稿がわかりづらいかもしれないため、改めて下に追記させていただきます。
スミマセン。(コードブロックも間違えておりました)
↓ ↓
以前教えていただいた検索フォームを作成中です。
そこで、教えていただいたサイトを参考に下記コードを作成しましたが、うまく動きません。

    Dim strFilter As String, strExp As String, aryOpe As Variant
'途中省略     
 
If Not IsNull(Me.txt伝票NO) Then
         strFilter = strFilter & " AND " & BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

    End If
         DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal

End Sub

①txt伝票NOに、改行区切りで入れられた複数の伝票NOについて
全て検索する。
②伝票NOは短いテキスト。

上記のコードを使うと「strFilter」のパラメータを聞いてきます。
エラー行は
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal です。

7
セロハン 2020/09/07 (月) 14:40:30 0029a@1c915 >> 3

以前教えていただいた検索フォームを作成中です。
そこで、教えていただいたサイトを参考に下記コードを作成しましたが、うまく動きません。

""" If Not IsNull(Me.txt伝票NO) Then
        strFilter = strFilter & " AND " & BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

    End If
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal
"""

①txt伝票NOに、改行区切りで入れられた複数の伝票NOについて
全て検索する。
②伝票NOは短いテキスト。

このコードを使うと「strFilter」のパラメータを聞いてきます。
エラー業は
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal です。

5
tetsusi 2020/09/07 (月) 14:24:46 28ccc@a46a9

デザインビューで試してみたところ4件、5件と追加できていました…
正直なところ2016でなぜこのエラーが出るのか分かりません

4
hatena 2020/09/07 (月) 13:07:09 修正

手元にあるフォームで試してみましたが、6件登録してもエラーにはなりませんでした。

テーブルとか作るのは面倒なので、色は配列にしました。

Private Sub Form_Load()
    Dim Fmt As FormatCondition

    Dim Colors
    Colors = Array(vbRed, vbGreen, vbYellow, vbBlue, vbMagenta, vbCyan)
    With Me!名前.FormatConditions
        .Delete
        Dim i As Long
        For i = 0 To UBound(Colors)
           Set Fmt = .Add(acExpression, acEqual, "[ID]=" & i + 1)
           Fmt.ForeColor = Colors(i)
        Next
    End With
End Sub

画像1

Access2019ですので、ひょっとしてバージョンで違うのかな。
デザインビューで手作業で条件書式を追加したときは4件以上でも登録できますか。

12
hiroton 2020/09/07 (月) 10:53:09 2d6b2@f966d

キーワードが「汎用関数」よりも「ユーザー定義関数」のほうが欲しい情報がより多く見つかるだろうくらいの話なのでその「使いどころ」は気にしなくていいですよ

4
hiroton 2020/09/07 (月) 10:26:31 2d6b2@f966d

「サロゲートキー」「ナチュラルキー」という考え方があります

例えば、「型番」なんかはユニークであることも多いのでそのまま主キーとしたりすることがあります。英数混合だったりするとテキスト型である必要があったりもします

でもだいたい「型番」がユニークかどうかわからないという恐怖体験を味わうのでIDフィールドを作ってオートナンバー振ってしまいます

実務では、このように混在させることはよくあることなのでしょうか?

必要に応じて設定すればおのずとそうなるというものですね。また、外部とデータのやり取りをする場合はどうしてもデータ的にはテキスト型(文字列)となってしまうので、インポート時に数値に変換するというのもよくある話です。今回の質問も雰囲気的には数値型に変えてしまってもいいように見えます


「00000」が存在するので、新規が全部「00000」のデータになってしまい諦めました。

テーブル設計でフィールドの規定値を設定すると回避できます。数値型のフィールドはデフォルトの規定値が「0」なのでこの値を変える(または削除する)と良いでしょう

2
tetsusi 2020/09/07 (月) 10:21:18 28ccc@a46a9

ありがとうございます
実際のコードは以下のようになっています

Dim Db      As DAO.Database
Dim Rs      As Recordset
Dim StrSQL  As String
Dim Fmt     As FormatCondition

Private Sub Form_Load()
    Set Db = CurrentDb
    StrSQL = "SELECT DISTINCT 文字色 FROM 項目MT ORDER BY 文字色"
    Set Rs = Db.OpenRecordset(StrSQL, dbOpenSnapshot)
    Me!項目.FormatConditions.Delete  →ここで削除してるはず
    Do Until Rs.EOF = True
        Set Fmt = Me!項目.FormatConditions.Add(acExpression, acEqual, "[文字色] = " & Rs!文字色)
        Fmt.ForeColor = Rs!文字色  → ループ4回目のここでエラーになります
        Rs.MoveNext
    Loop
End Sub

11
ポンタ 2020/09/07 (月) 10:11:18 0029a@1c915

お気にかけてくださり、ありがとうございます。
とりあえず値渡しで、変数の中身だけ変えてそれぞれの処理を呼び出すようにすることはできるようになりました。
ユーザー定義関数の使いどころはピンときていないので、コード、説明等書き換える時間が取れたらまた相談させていただきたいです。その際は宜しくお願いいたします。

10
hiroton 2020/09/07 (月) 08:14:38 2d6b2@f966d

一度ユーザー定義関数をキーワードに調べてみることをおすすめします

6

下記の関数を作成して、

Public Sub CtlVCenter2(ReportName As String, ControlName As String, ControlName1 As String, ControlName2 As String)
    DoCmd.OpenReport ReportName, acViewDesign
    
    Dim R As Access.Report
    Set R = Reports(ReportName)
    
    Dim C As Access.Control
    Set C = R.Controls(ControlName)
    Dim C1 As Access.Control
    Set C1 = R.Controls(ControlName1)
    Dim C2 As Access.Control
    Set C2 = R.Controls(ControlName2)
    
    C.Top = (C1.Top + C2.Top) / 2
End Sub

イミディエイトで下記を実行。

Call CtlVCenter2("レポート名", "フィールド3", "フィールド1", "フィールド2")

以上でどうでしょうか。

5

フィールドを挟むように線を二本引いて
上下の間隔を均等にする、をすると対処できるようですね

4

ありがとうございました

レポートの真ん中に移動されましたが
先述しました、あるフィールドを中央として配置することは不可能ですか?

フィールド1
      フィールド3
フィールド2

ということです

3

標準もモジュールに下記のような関数を作成します。

Public Sub CtlVCenter(ReportName As String, ControlName As String)
    DoCmd.OpenReport ReportName, acViewDesign
    
    Dim R As Access.Report
    Set R = Reports(ReportName)
    
    Dim C As Access.Control
    Set C = R.Controls(ControlName)
    
    C.Top = (R.Section(C.Section).Height / 2) - (C.Height / 2)
End Sub

イミディエイトウィンドウで下記のように記述してEnterキーを押します。

Call CtlVCenter("レポート名", "コントロール名")

これで、レポートがデザインビューで開いて、指定したコントロールがセクションの上下中央位置に移動します。
デザインビューを確認して問題なければ保存して閉じれば完了です。

2

コードをよろしくおねがいします

1

基本的には目分量ですることになります。
もし、コントロール数が多くて大変という場合は、VBAで位置調整する方法もありますが、Accessの場合は1レコード分の位置調整だけなのでそれほど手間ではないと思いますが。

もし、ご希望ならVBAで位置調整するコードを提示できますけど。

3

あ!それぞれ別のテーブルの主キーということですね。よくみたらそう書いてありますね。
一つのテーブルにフォームから入力したり、インポートしたりすると読み違えてました(;^_^A

なら、それぞれのテーブルに適したデータ型にすればいいので、現状でも問題ないです。

ただ、外部のデータの場合、仕様が変わったりデータミスがあったりする可能性があるなら、別にオートナンバー型フィールドを追加して主キーにした方かいいかも知れません。
また、追加順が必要な場合もオートナンバー型のフィールドは必要ですね。インポートした場合、Accessは入力順を保持しないので。

1
hatena 2020/09/05 (土) 12:08:38 修正

商品フォームのレコードソースのテーブルに「最新購入日」のフィールドは作成済みですか。
作成していない場合は作成してくださいね。

そこで、コントロールソースとして
=DMax("購入日","T_案件","商品NO=forms![F_商品]![txt商品NO]")
と記載しております。

これでも、最新購入日は表示されますが、
サブフォームでレコードを追加したり、購入日を編集しても、反映されませんよね。
反映された方がいいですよね。

サブフォームのフォームヘッダーかフッターにテキストボックスを配置して下記のように設定します。

名前 最新購入日
コントロールソース =Max([購入日])

メインフォームの最新購入日を表示するテキストボックスは、下記のように設定します。

名前 txt最新購入日
コントロールソース =[サブフォームコントロール名].Form![最新購入日]

これで、サブフォームで更新、追加して確定すると即反映されます。

これができたら、メインフォームの更新前処理のイベントプロシージャを下記のように記述します。

Private Sub Form_BeforeUpdate(Cancel As Integer)
    If Me!最新購入日 =  Me.txt最新購入日 Then
    Else
       Me!最新購入日 =  Me.txt最新購入日 
    End If
End Sub

これでテーブルに反映されます。

9
ポンタ 2020/09/05 (土) 11:46:55 0029a@1c915

お忙しいところお返事ありがとうございます。
そのままのコードをのせることが難しいのですが、
時間ができ次第、改めてわかりやすくまとめたいと思っています。
そのときは、またよろしくお願いいたします。

2
トマト 2020/09/05 (土) 11:01:24 0029a@1c915

わかりづらく、すみません。
以下のような形です。(実際はもっとテーブルがあるのですが)
テーブルB,Cにおいてオートナンバー型のフィールドを追加し、
主キーとした方がよいということでしょうか。
今のところ桁数もバラバラですが、わかりやすいようにあわせたりしますでしょうか。

●テーブルごとの主キー
テーブルAの商品ID 01(オートナンバー型の数値フィールド)
テーブルBの顧客ID 0001(外部のデータを常に既存のテーブルに追加インポート。短いテキスト)
テーブルCの会社ID 0001(外部のデータを常に既存のテーブルに追加インポート。短いテキスト)
テーブルDの担当者ID 001(オートナンバー型の数値フィールド)

1

Acc2016なら条件付き書式4件以上でも追加できるはずです。(最大何件かまでは把握してませんが。)
3件まではかなり前のバージョンだったと思います。

最初に条件付き書式を削除してから、追加してますか。

実際のコードを提示してください。

1

実務では、このように混在させることはよくあることなのでしょうか?

ないです(キッパリ)。

ただ、その説明では曖昧な部分があるので、下記の点について補足してもらえますか。

数値は、フォーム入力データでオートナンバーです。

この「オートナンバー」というのは「オートナンバー型」のフィールドという意味ではなく、
VBAかなんかで自動採番する機能を実装しているという意味ですよね。

短いテキストは、元データがあってひっぱってきたID

外部のデータを既存のテーブルに追加インポートしたということですか。

あと、具体的に主キーフィールドにどのような値が格納されているか例示してもらえますか。

たぶん、下記のような設定にすればいいとは思います。
オートナンバー型のフィールドを追加してそれを主キーとする。
外部データのID(テキスト型)、フォームで自動採番したID(数値型) はそれぞれ別のフィールドにする。

1
トマト 2020/09/04 (金) 15:11:16 0029a@1c915

こちらのバグ…なおりました。
全てのテーブルをXML形式でインポートしなおしたつもりでしたが、1つずつ確認していたところ関係なさそうなテーブルが漏れていたので、インポートしなおしたところ、エラー表示が出なくなりました。
この件で数時間トライ&エラーの繰り返しだったので、またすぐに発生するような気がしてトラウマ気味です。

3

操作しているフォームから、他のフォームを操作するには、Forms!かと思いましたが、

その認識で合ってますが、Forms!で参照する場合はフォームは開いている必要があります。
今回は、開く前に確認したいので、フォームのレコードソースのクエリの該当レコードのフィールド値を参照するために、
DLookup関数を使ったということです。

2
hideki 2020/09/03 (木) 17:27:26 09c37@96514

回答ありがとうございます。
Sub または、Functionが・・・・ で、反転するコード自体が無かったので、
hatena様の仰るとおり、コード自体に問題があると思っていました。

操作しているフォームから、他のフォームを操作するには、Forms!かと思いましたが、
提示されたコードでできるんですね。
勉強になりました。
ありがとうございました。

8
hatena 2020/09/03 (木) 15:59:36 修正

Private Sub から書いてもらえますか。

    Dim aName As String: aName = Test1.txt
この Test1.txt ってなんですか。

    Dim fText As Stirng: eText = "test5\"
    Dim gText As String: fText = "test6\"

ここは、

    Dim fText As Stirng: fText = "test5\"
    Dim gText As String: gText = "test6\"

の書き間違いですか。

正常に動いているものに対して、一括置換しました。

正常に動いているものをそのままコピーして貼り付けてもらうのはダメですか。

あと、どのようなことをしたいのか箇条書きの文章で説明してもらえますか。
それから汎用にする場合、どこが変化して、どこが共通なのか分かるように説明してください。

このようにやりたいことを分析して他人にも伝わるよう整理することはプログラミングにおいて大切なことです。
人間に伝わらないことを、それより融通のきかないコンピュータに伝えて正しく動作させることは不可能です。

1

提示されているコードにも問題がありますが、「Sub または、Functionが・・・・」というエラーがでるなら、それは別の部分のエラーである可能性が高いですね。
そのエラーがでたときに、「デバッグ」をクリックしたときに反転表示されるコードの前後も提示してください。

とりあえず提示されている部分を修正するなら、

IF DLookup("レコードロック", "Q_顧客データ", "顧客ID=" & Me.顧客ID)= True Then
    MsgBox "他人が利用中です。"
Else
    DoCmd.OpenOpen "F_詳細データ", , , "顧客ID=" & Me.顧客ID
End If
4
トマト 2020/09/03 (木) 15:16:52 0029a@1c915

そうだったんですね…大変失礼いたしました。ありがとうございました。

2
ワッフル 2020/09/03 (木) 13:41:01 f4a02@7602d

迅速なご返答ありがとうございます。
それから、ご返信が遅れてしまい、
まことに申し訳ございません。

リッチテキストについてちょっと調べてみようと
思います。

まだ、よく理解できないようなら、
ここにまた質問させてください。

7
ポンタ 2020/09/03 (木) 12:15:02 0029a@1c915
Dim aName As String :aName = test1.txt
Dim bPath As String :bPath = "C:\Users\me\Desktop\test2
Dim cPath As String :cPath = "C:\Users\me\Desktop\test3"
Dim dText As String :dText = "test4\"
Dim fText As Stirng :eText = "test5\"
Dim gText As String :fText = "test6\"

    If IsNull(Me.txt●●) Then
    MsgBox gText & "を記入してください"
    Exit Sub
            ElseIf AcDir(bPath, vbDirectory) = "" Then
            MsgBox "フォルダが存在しません。"
            Exit Sub
                 ElseIf AcDir(bPath & "\" & aName, vbNormal) = "" Then
                 MsgBox aName & "が見つかりません。"
                 Exit Sub
                      ElseIf AcDir(cPath & "\" & dText, vbDirectory) <> "" Then
                      FileCopy bPath & "\" & aName, cPath & "\" & dText & "\" & aName
                      Shell "Explorer.exe " & cPath & "\" & dText & "\", vbNormalFocus
                      Exit Sub
                            ElseIf AcDir(cPath & fText, vbDirectory) <> "" Then
                            MsgBox "「" & dText & "」フォルダが見つかりません。「" & fText & "」フォルダに保存します。"
                            FileCopy bPath & "\" & aName, cPath & "\" & fText & "\" & aName
                            Shell "Explorer.exe " & cPath & "\" & fText & "\", vbNormalFocus
                            Exit Sub
                                Else: MsgBox "「" & dText & "」「" & fText & "」フォルダのどちらも見つかりません。"
                                         Shell "Explorer.exe " & cPath, vbNormalFocus
                                
    End If
    End Sub

一応、私の確認したところでは正常に動いているものに対して、一括置換しました。
不備あれば申し訳ありません。

3

そのコードだと開いてないとダメですね。
下記のコードだと開いてなくても、開いていても大丈夫です。

開いてない場合、フィルターがかかった状態で開きます。
開いている場合は、そのフォームがアクティブになってフィルターがかかります。

Private Sub btn今月分_Click()
    Docmd.OpenForm "F_注文", , ,"売上日 Between #" & Date & "# AND #" & DateAdd("m", 1, Date)-1 & "#"
End Sub
2
トマト 2020/09/03 (木) 11:52:22 0029a@1c915

別のフォームです。フォームは開いていません。
開いていないとダメなんでしたっけ…理解不足で申し訳ありません。。

11
名前なし 2020/09/03 (木) 11:36:14 09c37@96514

ご回答いただきましてありがとうございました。
返信がおくれて大変申し分けありませんでした。
本当に感謝します。
ありがとうございました。