Microsoft Access 掲示板

6,727 件中 361 から 400 までを表示しています。
4
beginner 2025/02/20 (木) 13:56:20 61dd6@f300d

hatenaさん コードは下記です
” Dim rptName As String, opg1 As Integer, opg2 As Integer
    Dim txKubun As String, txSort As String, stArgs As String

    rptName = "R年度別売上集計_Cross_顧客と営業担当別"
    opg1 = Me.[opg_kubun].Value
    opg2 = Me.[opg_Sort].Value

    Select Case opg1 '担当区分
        Case 1
          txKubun = "社内営業担当:設定なし"
        Case 2
          txKubun = "社内営業担当:A"
        Case 3
          txKubun = "社内営業担当:B"
    End Select

    Select Case opg2 '並べ替え設定
        Case 1
          txSort = "※顧客社名で並べ替え"
        Case 2
          txSort = "●顧客合計金額を昇順で設定"
        Case 3
          txSort = "■顧客合計金額を降順で設定"
    End Select

    'レポートに渡すOpenArgsを組立
    stArgs = txKubun & "," & txSort

    MsgBox stArgs

    DoCmd.OpenReport rptName, acViewPreview, WhereCondition:=Me.Filter, OpenArgs:=stArgs
    DoCmd.Maximize  ”

  OpenArgsはレポートFormat時イベントに下記でしてます(念の為にレポートの非表示テキストボックス[tx_Args]のコントロールに設定してます)
   ” 'フォームからのOpenArgs[tx_Args]を分割して代入
       Dim v As Variant
       v = Split(Nz(Me.[tx_Args]), ",")
       Me.tx_kubun = v(0)
       Me.tx_sort = v(1)  ”

3

フォームのレポート開くコマンドボタンの全コードを提示してください。
stArgsをどのように設定しているか知りたいので。

2
しおこんぶ 2025/02/20 (木) 12:05:42 a6738@80964 >> 1

ありがとうございます。
「書式設定とレイアウトを保持したままデータをエクスポートする」もいれてるんですが、00.00のままです…
意味あるか分かりませんが、テーブルの書式変更してる最中です…

2
beginner 2025/02/20 (木) 11:58:42 61dd6@f300d

hatenaさん ありがとうございます。
フォームのオプションボタンopg2を下記でしてます
Select Case opg2 '並び替え設定
        Case 1
          Me.OrderBy = "[ふりがな] ASC"
        Case 2
          Me.OrderBy = "[顧客合計] ASC"
        Case 3
          Me.OrderBy = "[顧客合計] DESC"
    End Select

    Me.OrderByOn = True

レポートのレコードソースはフォームと同じクロス集計クエリを使ってます。

1

エクスポートするときに
「書式設定とレイアウトを保持したままデータをエクスポートする」のオプションにチェックを入れて実行したらどうでしょう。

1

現状、フォームの並べ替えはどのようにしていますか。

OrderByプロパティを利用しているのなら、それをOpenArgs引数でレポートに渡してレポート側でOrderByプロパティに設定すればいいでしょう。ただ、現状のコードをみるとOpenArgs引数はすでに利用しているようなので工夫が必要です。

レコードソースのクエリで並べ替えをしているなら、その並べ替えの設定をレポートのレコードソースにも反映させることになります。

どちらにしても、現状、フォームの並べ替えをどのようにしているかの詳細な情報が必要です。

2

そのクエリをどのようなレイアウトでレポートに出力したいのでしょうか。

サブレポートを使わなくても、レポートは機能豊富ですのでたいていのものは作成できます。
私自身はサブレポートを使うことはほとんどありません。

例えば、下記のようなレイアウトで出力したいのなら、
品目ID と 名称 の「重複データ非表示」プロパティを「はい」にするだけです。

品目ID   名称   数量   単価
A01   サンプル   50   500
                     40   400
                     30   250

ほかにもグループ化の機能をつかってグループヘッダー、グループフッターをうまく使えばたいていの帳票レイアウトは可能です。

4
ヘンリー 2025/02/20 (木) 10:14:06 df814@74a06

皆様、ご回答ありがとうございます。
おかげさまでできました。

hatena様、副クエリの作り方を教えていただきありがとうございます。

sk様、"00001"が決め打ちなのは、M_部屋がの構成が以下の通りだからです。
【M_部屋】
物件ID
棟ID
フロアID
部屋ID


部屋IDは、棟IDごと、フロアIDごとに、"00001"、"00002"…とあり、
棟ごとフロアごとの部屋数ではなく、棟ごとの部屋数だけを表示したいためです。

朱様
hatena様の例をもとに、1から作り直してみたので、
エラーの原因は後ほど確認してみます。

ユーザレビューを行った結果、少し仕様が変わり、M_部屋にデータがなくても、
棟名と棟ごとのフロア数は表示してほしいとの事でした。
出来上がったものを掲載しておきます。

SELECT
  M_棟.物件ID, M_棟.棟名, Q_F.[フロア数], Q_R.部屋数
FROM
  (M_棟 INNER JOIN
     (
      SELECT M_棟.物件ID, M_棟.棟ID, M_棟.棟名, Count(M_フロア.[フロアID]) AS フロア数
      FROM M_棟
      INNER JOIN M_フロア
      ON M_棟.物件ID = M_フロア.物件ID AND M_棟.棟ID = M_フロア.棟ID
      GROUP BY M_棟.物件ID, M_棟.棟ID, M_棟.棟名
     ) AS Q_F
   ON M_棟.物件ID = Q_F.物件ID AND M_棟.棟ID = Q_F.棟ID
  )
  LEFT JOIN
     (
      SELECT M_部屋.物件ID, M_フロア.棟ID, M_棟.棟名, M_部屋.[フロアID], Count(M_部屋.部屋ID) AS 部屋数
      FROM
      (M_棟 INNER JOIN M_フロア ON M_棟.物件ID = M_フロア.物件ID AND M_棟.棟ID = M_フロア.棟ID)
      INNER JOIN M_部屋
      ON M_フロア.物件ID = M_部屋.物件ID AND M_フロア.棟ID = M_部屋.棟ID AND M_フロア.[フロアID] = M_部屋.[フロアID]
      WHERE M_部屋.[フロアID]='00001'
      GROUP BY M_部屋.物件ID, M_フロア.棟ID, M_棟.棟名, M_部屋.[フロアID]
     ) AS Q_R
   ON M_棟.物件ID = Q_R.物件ID AND M_棟.棟ID = Q_R.棟ID
WHERE M_棟.物件ID='00165'

3

Accsessでは一番外側のWHERE以下以外で項目以外を条件に指定するとなぜかエラーになったような。
【エラーの出るSQL文】で途中に入ってる((M_棟.物件ID)="00165")がエラーの原因でしょうか。
提示されている【Q_F】【Q_R】にはないのに、なぜいきなり出てきた?という気はしますが。

1
かーか 2025/02/20 (木) 09:11:11 c409b@63c3a

数量と単価の関係性を逆にかいてしまいました。数量が多い方が安い見積りです。
質問内容とは関係ないかもしれませんが。。。

9
beginner 2025/02/19 (水) 16:05:03 61dd6@f300d

その後、期日の方も下記で出来ました(少し苦労しましたが)
”Function 支払期日(支払月間 As Variant, 支払日間 As Variant, 締め日付 As Date, 支払実日 As Variant) As Date

      If IsNull([支払月間]) Then
           支払期日 = DateAdd("d", [支払日間], [締め日付])
      Else
           支払期日 = DateSerial(Year([締め日付]), Month([締め日付]) + [支払月間], [支払実日])
           If [支払実日] = 0 Then 支払期日 = DateSerial(Year([締め日付]), Month([締め日付]) + [支払月間] + 1, [支払実日])
      End If

End Function”

hirotonさん色々と貴重なアドバイスありがとうございました。hatenaさんも毎回ありがとうございます。

8
beginner 2025/02/19 (水) 14:31:09 61dd6@f300d

hatenaさん ありがとうございました。勉強になります。
関数結果を細かく見ると10/31(正)が10/30(誤)になったりしてましたが、下記で正確にいけました。
”If Day(売上日付) > 締め実日 Then 締め日付 =  DateSerial(Year(売上日付), Month(売上日付) +1,締め実日)”
ちょっと焦りましたが、これでいけました。
大変お世話になりました。

7

If文は複数行で書く構文と、1行で書く構文があります。
1行構文

If 条件式 Then 真の処理 [Else 偽の処理]

複数行構文

If 条件式 Then
  真の処理 ・・・ 条件式を満たした場合の処理
[Else
  偽の処理] ・・・ 条件式を満たさない場合の処理
End If

条件が成立するときに実行するときのステートメントが一つのときは1行で書くことができます。(複数行でかいてもいいですが。)

つまり、

        If Day(売上日付) > 締め実日 Then 締め日付 = DateAdd("m", 1, 締め日付) 

は、下記と同等です。

        If Day(売上日付) > 締め実日 Then
             締め日付 = DateAdd("m", 1, 締め日付) 
        End If

hirotonさんから適切なアドバイスがありますが、変数の型は省略しない方がいいというのは私も同意見です。

Accessの場合は、フィールドの値を引数とすることが多くなるので、フィールドのデータ型やプロパティ設定と合わせるのがいいでしょう。

Null値になる可能性がある(値要求=いいえの場合)ならVariant型、
Null値になる可能性がない(値要求=はいの場合)ならフィールドのデータ型と同じにする。

戻り値の型もNull値を返す必要性がある場合はVariant型、Null値を返す必要性がない場合は想定する型で宣言します。

6
beginner 2025/02/19 (水) 12:56:02 61dd6@f300d

色々詳細をありがとうございました。支払実日の0は末日になります。関数に出来ました。
”Else
        締め日付 = DateSerial(Year(売上日付), Month(売上日付), 締め実日)
        If Day(売上日付) > 締め実日 Then 締め日付 = DateAdd("m", 1, 締め日付) ” の様な記述ができるのですね。初めて知りました。この場合Ifが2つあってもEnd Ifは1つなのですね。

5
hiroton 2025/02/19 (水) 10:20:41 116a6@f966d

質問文を頑張って読み取って「支払実日の0は末日指定なのだろう」と思ってますが合ってますよね?

4
hiroton 2025/02/19 (水) 10:09:39 116a6@f966d

※VBAで解釈できない計算式(SQL記述)の場合はこの方法ではうまくいかない場合があります
ろくに計算式を見ないで回答してしまっていてアレなんですが、今回の内容だけでもNULLの判定はVBA用の記述にする必要がありますね

締め実日 Is Null
↓
IsNull(締め実日)

※VBA記述のマナーは無視しているので~
VBA記述には省略可能なものがありますが、記述しておくのが一般的なものや、問題なくとも意味合いが正確でないものもあります

Function ステートメント
ざっくりいうと、データ型はしっかり記述したほうが良いです

Function 締め日付(締め実日, 売上日付)
↓
Function 締め日付(締め実日 As Variant, 売上日付 As Date) As Date

締め実日はNULLを扱うため、Variant型である必要があります。また、データ型の省略時はVariant型となるため、省略しても同じですが、明示することにより、NULLを扱うことがあるし、それを意図してやっているということが読み取れるようになります
逆に、そのほかの引数についてはしっかりそれぞれのデータ型を使うと指定(制限)をしておきましょう

関数の戻り値のデータ型

Function 締め日付(締め実日 As Variant, 売上日付 As Date) As Date

を記述するかどうかは個人差が出そうですが、日付型なら日付型を指定しておくと諸所で日付型のデータとして扱ってくれるのでよりよいと思われます(文字配置の「標準」が右寄せになったりとか)

あと、変数の名前からデータの内容がいまいち正確でないものには何か手を入れたほうがいいです

Function 支払期日(支払月間, 支払日間, 締め日付, 支払実日)
↓
Function 支払期日(支払月間, 支払日間, 締め日付, 支払実日)
'支払実日が「0」は末日指定を表す

「日付」に「0日」はありませんし、「0の指定が1の1つ前ではない」ので、直感と実態が合わなくなります。末日指定をどうデータベース化するか?は悩みどころではありますが、とりあえず今回はコメント記述で対応ということで

あとはまぁ、「1行で記述する必要はない」ので、入れ子になりすぎて見づらい記述を分解するとかですかね。どこまでやるかはその時の内容次第です

3
hatena 2025/02/19 (水) 09:41:11 修正 >> 2

VBAは、Is Null は使えないので、代わりにIsNull関数を使います。

Function 締め日付(締め実日, 売上日付)
    締め日付 = IIf(IsNull(締め実日), 売上日付, DateSerial(Year(売上日付), Month(売上日付) + IIf(Day(売上日付) > 締め実日, 1, 0), 締め実日))
End Function

あと、VBAを使うならIf構文を使った方が読みやすいように思います。

Function 締め日付(締め実日, 売上日付)
    If IsNull(締め実日) Then
        締め日付 = 売上日付
    Else
        締め日付 = DateSerial(Year(売上日付), Month(売上日付), 締め実日)
        If Day(売上日付) > 締め実日 Then 締め日付 = DateAdd("m", 1, 締め日付)
    End If
End Function
2
beginner 2025/02/19 (水) 08:41:24 61dd6@f300d

hirotonさん ありがとうございます。
”※VBAで解釈できない計算式(SQL記述)の場合はこの方法ではうまくいかない場合があります
※VBA記述のマナーは無視しているので、ユーザー定義関数がうまく動作することが確認出来たらVBA記述として望ましい記述か?を別途見直してみるとよいです”とありますが、マナー無視している事になるのでしょうか?(すみません知識不足で)

2

"00165"の部分は変数で扱っています。

M_部屋.[フロアID])="00001"

[M_部屋]の[フロアID]に対する条件値は固定なのでしょうか。
それとも、その部分も変数で指定しているのでしょうか。

もし前者である場合、"00001"を指定しているのはどのような理由からなのでしょうか。

1
hiroton 2025/02/18 (火) 17:51:38 1b258@f966d

コード(SQL構文、計算式等)をそのまま記述するとこの掲示板用のMarkdown記述と解釈されて意図しない整形がされてしまうことがあるので、コードブロックを使って記述しましょう


もっとも単純には、計算式で指定しているフィールドを重複を省いて引数において、そのまま戻り値に計算式を指定し、フィールド部分を引数に置き換えればユーザー定義関数化ができます

Function 締め日付(締め実日, 売上日付)
    締め日付 = IIf(締め実日 Is Null, 売上日付, DateSerial(Year(売上日付), Month(売上日付) + IIf(Day(売上日付) > 締め実日, 1, 0), 締め実日))
End Function
Function 支払期日(支払月間, 支払日間, 締め日付, 支払実日)
    支払期日 = IIf([支払月間] Is Null, DateAdd("d", [支払日間], [締め日付]), DateSerial(Year([締め日付]), Month([締め日付]) + [支払月間] + IIf([支払実日] = 0, 1, 0), [支払実日]))
End Function

※VBAで解釈できない計算式(SQL記述)の場合はこの方法ではうまくいかない場合があります
※VBA記述のマナーは無視しているので、ユーザー定義関数がうまく動作することが確認出来たらVBA記述として望ましい記述か?を別途見直してみるとよいです

クエリで使うときはそれぞれ

締め日付: 締め日付([締め実日],[売上日付])
支払期日: 支払期日([支払月間],[支払日間],[締め日付],[支払実日])

または、締め日付を求めずに支払期日を求める場合は、支払期日の締め日付指定部分に締め日付を求める関数を指定すればよいでしょう

支払期日: 支払期日([支払月間],[支払日間],締め日付([締め実日],[売上日付]),[支払実日])
1

質問の結構複雑なSQLを読み解くのは骨なので、
私が複数クエリをサブクエリを使って一つにまとめる場合の手法を紹介しておきます。

まず、クエリデザインビューから作成したSQLは不必要な()が多くなり読みづらいので、不要なカッコは除去します。
その後、階層関係が分かりやすいように適切なインデントを付けて読みやすくします。
インデントの付け方は人それぞれの好みがあるので工夫して自分が読みやすいようにしてください。

例えば質問の最初のSQLなら、自分なら下記のようにします。

SELECT
  M_棟.物件ID, M_棟.棟名, Q_F.[フロア数], Q_R.部屋数
FROM
  (M_棟 INNER JOIN Q_F
     ON M_棟.棟ID = Q_F.棟ID AND M_棟.物件ID = Q_F.物件ID)
  INNER JOIN Q_R 
    ON M_棟.棟ID = Q_R.棟ID AND M_棟.物件ID = Q_R.物件ID
WHERE M_棟.物件ID="00165";

つぎにサブクエリにしたいクエリ名(Q_F, Q_R)の前に下記のように () AS を挿入します。

SELECT
  M_棟.物件ID, M_棟.棟名, Q_F.[フロア数], Q_R.部屋数
FROM
  (M_棟 INNER JOIN () AS Q_F
     ON M_棟.棟ID = Q_F.棟ID AND M_棟.物件ID = Q_F.物件ID)
  INNER JOIN () AS Q_R 
    ON M_棟.棟ID = Q_R.棟ID AND M_棟.物件ID = Q_R.物件ID
WHERE M_棟.物件ID="00165";

この挿入したカッコの中に、それぞれのクエリのSQLを挿入します。

もちろん挿入する前にそれぞれのSQLも読みやすいようにインデントを入れておきます。

すると下記のような感じになります。

SELECT
  M_棟.物件ID, M_棟.棟名, Q_F.[フロア数], Q_R.部屋数
FROM
  (M_棟 INNER JOIN
    (     
      SELECT
        M_棟.物件ID, M_棟.棟ID, M_棟.棟名, Count(M_フロア.[フロアID]) AS フロア数
      FROM
        M_棟 INNER JOIN M_フロア
          ON M_棟.棟ID = M_フロア.棟ID AND M_棟.物件ID = M_フロア.物件ID
      GROUP BY M_棟.物件ID, M_棟.棟ID, M_棟.棟名
    ) AS Q_F
     ON M_棟.棟ID = Q_F.棟ID AND M_棟.物件ID = Q_F.物件ID
  )
  INNER JOIN
    (
      SELECT
        M_部屋.物件ID, M_フロア.棟ID, M_棟.棟名, M_部屋.[フロアID], Count(M_部屋.部屋ID) AS 部屋数
      FROM
        (M_棟 INNER JOIN M_フロア
          ON M_棟.物件ID = M_フロア.物件ID AND M_棟.棟ID = M_フロア.棟ID)
        INNER JOIN M_部屋
          ON M_フロア.物件ID = M_部屋.物件ID AND M_フロア.棟ID = M_部屋.棟ID AND M_フロア.[フロアID] = M_部屋.[フロアID]
      GROUP BY M_部屋.物件ID, M_フロア.棟ID, M_棟.棟名, M_部屋.[フロアID]
    ) AS Q_R 
      ON M_棟.棟ID = Q_R.棟ID AND M_棟.物件ID = Q_R.物件ID
WHERE M_棟.物件ID)="00165";

提示のSQLを機械的につなげただけのものなので、希望の結果になるかどうかはそちらでしっかり確認してください。

2

回答ありがとうございました。
前からの仕様だったのですね。失礼いたしました。
バージョン管理も参考とさせていただきます。
ありがとうございました。

2
beginner 2025/02/13 (木) 08:47:52 61dd6@d3cb5

hatenaさん ありがとうございます。すごいアイデアですね。参考にしてみます。
お世話になりました。

1

エクスポート先の本番用ファイル内のフォームがそうなるということですか。
当方の環境は365ですが、確認してみたらそうなりますね。

私のブログの下記の記事によると、「エクスポートすると作成日、更新日ともエクスポートした日時になります」とのことですので、当時(2015年)からそのような仕様だったようですがが。

オブジェクトの説明プロパティの取得・設定関数
説明プロパティとはナビゲーションウィンドウのオブジェクトアイコンを右クリック-[***のプロパティ]ででる説明のことです。 これをVBAから簡単に取得したり、設定したりする関数です。 難易度:...
Fc2

上記の記事では、説明プロパティにバージョン情報を入力しておいて、それを利用してはどうかと提案してます。

ちなみに、私も開発用と本番用は分けてますが、開発用で更新した場合は個別にエクスポートせずにファイルごと上書きしてますので、そのようなことで困ったことはないです。

ファイルのバージョン管理は、バージョン管理用のテーブルを作成して、そこにバージョンNo、更新日を格納して利用してます。

オブジェクトを個別にエクスポートすると、ファイル破損の危険性が高いような気がしますので、開発用のファイルを更新したら、開発用府。イルを最適化してから本番用ファイルに上書きするという方法をとってます。古い記事ですが下記もご参考に。

複数ユーザーで共有している場合のフロントエンドファイルのバージョンアップ - hatena chips

1

今回したい事は請求書を発行済みかどうかのフラグがフォームに展開出来たらいいなと思ってます。
自動的にフラグを立てる必用はなくYes/Noボタンかコマンドボタンでしたいです。
発行済みというフィールドはないので(あってもグループ集計クエリでは編集不可になるので)、そういう事は無理でしょうか?

「発行済みというフィールド」がないのに、どのようにフォーム上に展開するのでしょうか。

それとも、そのフラグを保存する必要はなくその場限りのものでいいのなら、下記のページの方法が利用できます。

非連結のチェックボックスでレコードを選択する
帳票フォームでチェックボックスを配置して、チェックしたレコードのみ選択して印刷したいのですが、一つのレコードをチェックするとすべてのレコードが選択されてしまいます。 掲示板でたまにみかける質問です。気持ちは分かりますが、非連結コントロールでの更新はすべてのレコードに反映されてしまいます。一つのコントロールにプロパティ値は一つしかもてませんので。各レコード毎にプロパティ値を持つような設計にしたら大量...
fc2

2
あん 2025/02/05 (水) 13:01:56 b41ab@331d4

hatena様

1発解決でした!

そこそこ時間かけて四苦八苦しましたが、教えていただいた記述で1発でした。😮

ありがとうございました。

1
hatena 2025/02/05 (水) 12:24:13 修正

下記に修正してください。

Me.データ件数.ControlSource = "=DCount(""番号"", ""クエリ名"") & ""件"""

質問のコードだとコントロールソースには下記の式が設定されます。

=DCount("番号", "クエリ名") & 件

この場合「件」というフィールドかコントロールを参照しに行きますが、フォーム上にないのでName?エラーになります。
「件」は文字列でないとだめなので、引用符で囲む必要があります。

=DCount("番号", "クエリ名") & "件"
1
beginner 2025/02/04 (火) 13:15:33 61dd6@bd593

この件ですが解決しました。文字列型になっているのではと思いSQL最初のSELECT [売上年度], "" AS 年度合計の""を0にしたら通貨型になり、レポートでも設定できました。落ち着いて考えると分かる事でした。お騒がせしました。

5
beginner 2025/01/30 (木) 12:58:38 61dd6@7c1a3

hatenaさん ありがとうございます。
「開く時」「読み込み時」はCancel以外で出来る事が違うとは知りませんでした。大変勉強になります。
今回もお世話になり大変有り難うございました。

4
hatena 2025/01/30 (木) 11:00:30 修正

レポートの「開く時」イベントでは、デザインビューで設定できるプロパティのみ代入できます。
Valueプロパティには代入できません。

対策としては、ControlSourceプロパティに式として代入する。

Private Sub Report_Open(Cancel As Integer)
    Dim kikan As String
    kikan = Nz(Me.OpenArgs, "")
    Me.[text_kikan].ControlSource = "='" & kikan & "'"
End Sub

=や引用符を付加する必要があります。

「読み込み時」イベントならValueプロパティに代入できます。こちらのほうがシンプルですね。

Private Sub Report_Load()
    Dim kikan As String
    kikan = Nz(Me.OpenArgs, "")
    Me.[text_kikan].Value = kikan
End Sub

VBAを使わなくても、デザインビューでテキストボックスのコントロールソースでOpenArgsを参照することもできます。

=Nz([OpenArgs],"")

Report.OpenArgs プロパティ (Access) | Microsoft Learn

3
beginner 2025/01/30 (木) 08:30:07 61dd6@7c1a3

hatenaさん ありがとうございます。これで1つにまとめる事が出来ました。
引数の事も大体理解できました。関数の()内と同じなのですね。Functionも使いこなす事が出来たら便利ですね。別で関数にしたい事があり、これはまたいずれ投稿したいと思ってます。
この関連で別内容なのですがレポート開くイベントにOpenArgsをレポートの非連結のテキストボックスに代入しようとすると代入出来ないエラーとなります。ラベルには代入できます(表示だけなのでそれでもOKですが)。それは何故なのでしょうか?
ラベル代入は下記コードです(これならエラーでません)。
  Dim kikan As String
    kikan = Nz(Me.OpenArgs, "")
    Me.[label_kikan].Caption = kikan

2

引数の使い方が理解できたなら、
イベントプロシージャでCallで呼び出すのではなく、
フォームのデザインビューでイベントプロシージャに関数を設定して呼び出す方法も習得しておくといいでしょう。

Function PreviewReport(rptName As String)
    Dim cuDt1 As Variant, cuDt2 As Variant, urDt1 As Variant, urDt2 As Variant
    Dim stArgs1 As Variant, stArgs2 As Variant

    cuDt1 = Me.[cb売上年月Fr] & "/01"
    cuDt2 = CDate(Me.[cb売上年月To] & "/01")
    cuDt2 = DateSerial(Year(cuDt2), Month(cuDt2) + 1, 0)
    urDt1 = Me.[cb売上日付Fr]
    urDt2 = Me.[cb売上日付To]

    stArgs1 = "※指定期間: " & cuDt1 & "~" & cuDt2
    stArgs2 = "★指定期間: " & urDt1 & "~" & urDt2

    If IsNull(urDt2) Then
        DoCmd.OpenReport rptName, acViewPreview, OpenArgs:=stArgs1
    ElseIf Not IsNull(urDt2) Then
        DoCmd.OpenReport rptName, acViewPreview, OpenArgs:=stArgs2
    End If
End Function

SubをFunctionに変更しただけです。
フォームのデザインビューで「クリック時」プロパティに下記のように設定します。

=PreviewReport("●●●")

ボタン毎にイベントプロシージャを記述する必要がなく、Functionを作成しておけばフォームのデザインビューの設定で済みます。
私のはこの方法を多用してます。

1

各ボタンのコードがレポートのみの異なるだけであとは同じなので、一つのプロシージャにまとめたいということでしょうか。

レポート名は引数で渡せばいいでしょう。「引数ってなに?」というレベルなら下記あたりを参照してください。

第29話「引数と戻り値ってなに?」1/4:引数とは…?|VBAとの出会い編|VBAエキスパートコラム

フォームモジュール

Sub PreviewReport(rptName As String)
    Dim cuDt1 As Variant, cuDt2 As Variant, urDt1 As Variant, urDt2 As Variant
    Dim stArgs1 As Variant, stArgs2 As Variant

    cuDt1 = Me.[cb売上年月Fr] & "/01"
    cuDt2 = CDate(Me.[cb売上年月To] & "/01")
    cuDt2 = DateSerial(Year(cuDt2), Month(cuDt2) + 1, 0)
    urDt1 = Me.[cb売上日付Fr]
    urDt2 = Me.[cb売上日付To]

    stArgs1 = "※指定期間: " & cuDt1 & "~" & cuDt2
    stArgs2 = "★指定期間: " & urDt1 & "~" & urDt2

    If IsNull(urDt2) Then
        DoCmd.OpenReport rptName, acViewPreview, OpenArgs:=stArgs1
    ElseIf Not IsNull(urDt2) Then
        DoCmd.OpenReport rptName, acViewPreview, OpenArgs:=stArgs2
    End If
End Sub

Private Sub コマンド1_Click()
    Call PreviewReport("●●●")
End Sub

ご自身のコードと見比べればどこが変更されてるか一目だとおもいます。

5
hiroton 2025/01/27 (月) 09:26:34 629df@f966d >> 1

Web検索をしてみると、少し古い情報で、同様の不具合が起きていることがあるようですね。しかも結局解決には至っていないようでした。コピーアンドペーストはwindowsのクリップボード、officeのクリップボード、と、外部機能と連携して機能しているので、謎の不具合に見舞われた場合、個人で自身の環境を調査するしかないのかもしれません

VBAを使うことになりますが、コピーアンドペーストを使わないようにすると問題が起きにくいと思います。
参考:レコードをVBAでまるごとコピー

6

mayuさん、バグのご指摘ありがとうございます。
理由も含めてのていねいな解説、納得です。

5
mayu 2025/01/25 (土) 14:43:28 修正 fc5d2@6c788 >> 4

hatenaさんのコード、シンプルで素敵ですね
RemoveDuplicatesX 関数の内側ループ、終了の数値を 1 だけ足せば更に完璧かもです

-         For j = 1 To lA - i
+         For j = 1 To lA - i + 1
4
hatena 2025/01/25 (土) 11:06:02 修正 >> 2

Bの文字列で「 連続3文字以上で構成された語句でAに対する最長マッチ 」を繰り返す
と定義した場合、

mayuさんの上記の定義を仕様とする場合は下記のコードでもよさそう。

Function RemoveDuplicatesX(ByVal argA As Variant _
                      , ByVal argB As Variant _
                      , Optional ByVal argMinimum As Long = 3) As Variant
    RemoveDuplicatesX = argB
    Dim lA As Long, lB As Long, l As Long
    lA = Len(Nz(argA))
    lB = Len(Nz(argB))
    If lA < argMinimum Or lB < argMinimum Then Exit Function
    If lB < lA Then l = lB Else l = lA
    
    Dim i As Long, j As Long
    For i = l To argMinimum Step -1
        For j = 1 To lA - i
            RemoveDuplicatesX = Replace(RemoveDuplicatesX, Mid(argA, j, i), "")
        Next
    Next
End Function

Private Sub コマンドボタン名_Click()
    '// 重複と見なす文字列の最小連続長は関数の第三引数で指定します(省略時は3)
    Me.テキストボックスB.Value = _
        RemoveDuplicatesX(Me.テキストボックスA.Value, Me.テキストボックスB.Value)
End Sub
3
mayu 2025/01/25 (土) 09:19:49 修正 fc5d2@6c788 >> 1

慧眼のhatenaさんが仰せのように、もし 連続した複数文字列を対象 とするのでしたら
「連続」の定義、つまり最小で何文字連続している必要があるのか
を明確にする必要があるでしょう

テキストボックスA = "あいうえおかきく"
テキストボックスB = "[@あいうえお@おかき@きくうえお@いうえおかういあいうえおかきおかく]"

Bの文字列で「 連続3文字以上で構成された語句でAに対する最長マッチ 」を繰り返す
と定義した場合、

[@あいうえお@おかき@きくうえお@いうえおかういあいうえおかきおかく]

Bからは、背景色を付与した5箇所の語句を検知( グレーアウト部分は長さが不足 )し、
最終的に

テキストボックスB = "[@@@きく@ういおかく]"

をご希望の結果とするサンプルも載せておきます
 

Function OnesideUniqueX(ByVal argA As Variant _
                      , ByVal argB As Variant _
                      , Optional ByVal argMinimum As Long = 3 _
                      , Optional ByVal argPos As Long = 1) As Variant
    OnesideUniqueX = argB
    Dim i    As Long
    Dim j    As Long
    Dim buff As String

    If (LenB(Nz(argA)) = 0 Or LenB(Nz(argB)) = 0) Then Exit Function
    If (argMinimum < 1 Or argPos < 1) Then Exit Function

    For i = argPos To Len(argB) - argMinimum + 1
        If (InStr(1, argA, Mid$(argB, i, argMinimum), vbBinaryCompare) > 0) Then
            buff = Mid$(argB, i, argMinimum)

            For j = i + argMinimum To Len(argB)
                buff = buff & Mid$(argB, j, 1)
                If (InStr(1, argA, buff, vbBinaryCompare) = 0) Then
                    OnesideUniqueX = _
                        OnesideUniqueX(argA, Left$(argB, i - 1) & Mid$(argB, j), argMinimum, i)
                    Exit Function
                End If
            Next j
            OnesideUniqueX = Left$(argB, Len(argB) - Len(buff))
            Exit Function
        End If
    Next i
End Function

 

Private Sub コマンドボタン名_Click()
    '// 重複と見なす文字列の最小連続長は関数の第三引数で指定します
    Me.テキストボックスB.Value = _
        OnesideUniqueX(Me.テキストボックスA.Value, Me.テキストボックスB.Value, 3)
End Sub
2
hatena 2025/01/25 (土) 00:09:26 修正

例をみると連続した複数文字列を対象にするようにも思えますが、
一文字単位でも重複していれば削除するという仕様であれば、
mayuさんのコードでいいでしょう。
単純に下記でも同様の結果になります。

Function RemoveDuplicates(ByVal argA As Variant, ByVal argB As Variant) As Variant
    RemoveDuplicates = argB
    If argA <> "" And argB <> "" Then
        Dim i      As Long
        For i = 1 To Len(argA)
            RemoveDuplicates = Replace(RemoveDuplicates, Mid(argA, i, 1), "")
        Next i
    End If
End Function
1

テキストボックスA="あいうえおかきく"
テキストボックスB="かきくけこさしす"
のとき、"かきく" が重複していると判定し
テキストボックスB="けこさしす"に変換したい

シンプルに、テキストボックスBに入力された文字列を一文字ずつチェックしていけばいいでしょう
 

Function OnesideUnique(ByVal argA As Variant, ByVal argB As Variant) As Variant
    OnesideUnique = argB
    If (LenB(Nz(argA)) = 0 Or LenB(Nz(argB)) = 0) Then Exit Function
    Dim i      As Long
    Dim c      As Long
    Dim buff() As String
    
    For i = 1 To Len(argB)
        If (InStr(1, argA, Mid$(argB, i, 1), vbBinaryCompare) = 0) Then
            ReDim Preserve buff(c)
            buff(c) = Mid$(argB, i, 1)
            c = c + 1
        End If
    Next i
    If (UBound(buff) > -1) Then
        OnesideUnique = Join(buff, "")
    End If
End Function

 
テキストボックスA, Bともにフォーム上に設置したコントロールだと仮定すると
コマンドボタンのクリック時イベント等で結果を確認するといいでしょう

Private Sub コマンドボタン名_Click()
    Me.テキストボックスB.Value = _
        OnesideUnique(Me.テキストボックスA.Value, Me.テキストボックスB.Value)
End Sub