Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
最新の日付のデータをレポートで抽出したい
投稿日時: 21/03/30 10:48:06
投稿者: MAXBOX

Accessで辞令を作り印刷するシステムを作成しています。
ほとんどできあがりいざデータを登録して印刷しようとしたのですが
直近で昇格がありデータが登録されている人は、前のデータで辞令が出てきてしまいます。
初めて昇格する人や、昇格が合っても何年も前の人はちゃんと登録したデータが印刷されます。
これをすべて最新の日付データで印刷したいのですがどうしたらいいでしょうか?
 
下記にコードやテーブル構造など載せていきます。
 
☆辞令文テーブル
種類:短いテキスト
辞令文:長いテキスト
※辞令文テーブルの種類には昇格辞令、異動辞令など辞令文の種類が入力されます
 
☆辞令印刷フォーム
レコードソース:辞令文テーブル
フォームには辞令を印刷したい社員を選ぶコンボボックスと、その下には辞令文の種類を選ぶオプションボタンが配置しています。
社員と辞令の種類を選んで印刷ボタンを押すことで印刷したい辞令がプレビューで出てくる仕様になっています。
 
印刷ボタンのコードは下記です。

Private Sub 印刷_Click()

Dim strWhere As String
If 配属 Then strWhere = " OR [種類]='配属'"
If 昇格 Then strWhere = strWhere & " OR [種類]='昇格'"
If 異動 Then strWhere = strWhere & " OR [種類]='異動'"
If strWhere = "" Then Exit Sub

If Not IsNull(Me!cmb社員番号) Then _
strWhere = "(" & strWhere & ") AND [社員番号]=" & Me!cmb社員番号

If 配属 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_配属", acViewPreview, , strWhere, acDialog
If 昇格 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_昇格", acViewPreview, , strWhere, acDialog
If 異動 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_異動", acViewPreview, , strWhere, acDialog

End Sub

 
☆辞令レポートクエリ
社員の異動を登録するテーブルと辞令文テーブルを結合したクエリです。
種類でリレーションを組んでいます。
社員番号:数値型
氏名:テキスト型
発令日:日付型
種類:テキスト型
異動部署:テキスト型
辞令文:テキスト型(辞令文テーブルより)
 
以上になります。
 
私が実装したいのは最新の日付データ(発令日)でレポートを抽出することです。
情報が不足している場合は教えてください。
 
お手数ですが宜しくお願い致します。

回答
投稿日時: 21/03/30 14:14:01
投稿者: sk

引用:
ほとんどできあがりいざデータを登録して印刷しようとしたのですが
直近で昇格がありデータが登録されている人は、前のデータで辞令が出てきてしまいます

[発令日]に対する抽出条件を特に設けていないのであれば、
当然過去に発令された全ての辞令が出力対象となるでしょう。
 
引用:
初めて昇格する人や、昇格が合っても何年も前の人はちゃんと登録したデータが印刷されます。
これをすべて最新の日付データで印刷したいのですがどうしたらいいでしょうか?

・[発令日]の値が任意の日付である(日付範囲に含まれる)レコードを抽出したい。
 (例えば「 2020/04/01 から 2021/03/31 まで」とした場合、
 [発令日]の値がその範囲に含まれてさえいれば、1 人の社員につき
 1 件以上のレコードが出力されることになる)
 
・それぞれの社員ごとに「最後に出された辞令」に当たる
 ([発令日]の値が最大である)レコードを 1 件ずつ抽出したい。
 
どちらの意味でおっしゃっているのでしょうか。

投稿日時: 21/03/30 14:31:23
投稿者: MAXBOX

sk様
回答ありがとうございます。
 

引用:
それぞれの社員ごとに「最後に出された辞令」に当たる
 ([発令日]の値が最大である)レコードを 1 件ずつ抽出したい。

 
私がしたいことはこちらです。
発令日の値が最大の辞令を一件ずつ抽出したいです。
 
もしくは、発令日で指定してその発令日に該当する辞令文を印刷プレビューで出したいです。
 
どちらの方法も1人の社員につき1件の辞令文としたいです。
 
発令日に該当する辞令文を出す方法は新たに質問として追加してしまいましたが、どちらの方法も教えて頂きたいです。
宜しくお願い致します。

回答
投稿日時: 21/03/30 14:52:43
投稿者: sk

引用:
発令日の値が最大の辞令を一件ずつ抽出したいです。

引用:
☆辞令レポートクエリ
社員の異動を登録するテーブルと辞令文テーブルを結合したクエリです。
種類でリレーションを組んでいます。
社員番号:数値型
氏名:テキスト型
発令日:日付型
種類:テキスト型
異動部署:テキスト型
辞令文:テキスト型(辞令文テーブルより)

仮に[辞令文]以外の全てのフィールドが[異動履歴テーブル]から
参照されているとした場合は、例えば次のようなクエリを
作成して、レポートのレコードソースとしてみると
よいのではないでしょうか。
 
( SQL ビュー)
-------------------------------------------------------------------------------
SELECT [異動履歴テーブル].[社員番号],
       [異動履歴テーブル].[氏名],
       [異動履歴テーブル].[発令日],
       [異動履歴テーブル].[種類],
       [異動履歴テーブル].[異動部署],
       [辞令文テーブル].[辞令文]
FROM ([異動履歴テーブル]
      INNER JOIN (SELECT [異動履歴テーブル].[社員番号],
                         Max([異動履歴テーブル].[発令日]) AS [最新発令日]
                  FROM [異動履歴テーブル]
                  GROUP BY [異動履歴テーブル].[社員番号]) AS [社員別最新発令日]
       ON [異動履歴テーブル].[社員番号] = [社員別最新発令日].[社員番号]
      AND [異動履歴テーブル].[発令日] = [社員別最新発令日].[最新発令日])
LEFT JOIN [辞令文テーブル]
ON [異動履歴テーブル].[種類] = [辞令文テーブル].[種類]
ORDER BY [異動履歴テーブル].[社員番号],
         [異動履歴テーブル].[種類];
-------------------------------------------------------------------------------
 
引用:
もしくは、発令日で指定してその発令日に該当する辞令文を印刷プレビューで出したいです。

その場合は、[発令日]に対する条件値となる任意の日付を入力するための
非連結テキストボックスを[辞令印刷フォーム]上に追加することが
先決かと。
 
あとは既に記述されているコードと同じ要領で、
変数 strWhere に抽出条件式を追記なさればよろしいでしょう。
(日付/時刻リテラルの場合は ' ではなく # で囲むようにして下さい)

投稿日時: 21/04/02 08:59:37
投稿者: MAXBOX

sk様
お返事が大変遅くなり申し訳ありません。
 
教えて頂いたSQLを記載してみましたが、エラーが多発しこちらでは処理ができませんでした。。
せっかく教えて頂いたのに申し訳ありません。
 
日付で抽出する方法でも問題ないのでこちらを試したのですが実行時エラー3075「日付の構文エラー」と出ました。
ちなみに下記のコードに修正しました。

If Not IsNull(Me!発令日) Then _
strWhere = "(# & strWhere & #) AND [発令年月日]=" & Me!発令日

 
デバッグすると下記が黄色くなります。
 
If 配属 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_配属", acViewPreview, , strWhere, acDialog

 
お手数ですが修正方法を教えて頂きたいです。

回答
投稿日時: 21/04/02 10:48:16
投稿者: sk

引用:
教えて頂いたSQLを記載してみましたが、エラーが多発し
こちらでは処理ができませんでした。。

テーブル/フィールドの名前は実際のものを記述する必要がありますし
([異動履歴テーブル]は「社員の異動を登録するテーブル」の
正確な名前が明記されていないため、私が適当につけた仮の名前に過ぎない)、
また[異動履歴テーブル]や[辞令文テーブル]以外のテーブルから
参照しているフィールドがあるなら、それらも適宜修正する必要があります。
 
1. [異動履歴テーブル]の全てのレコードを[社員番号]でグループ化して
   グループごとに[発令日]の最大値を得る集計クエリを作成する。
 
2. 新たに作成したクエリ上で、[異動履歴テーブル]と 1 の集計クエリを
   [社員番号]と[発令日](の最大値)同士で内部結合する。
 
3. 更に[異動履歴テーブル]と[辞令文テーブル]を
   [種類]同士で外部結合する。
 
4. [異動履歴テーブル]から全てのフィールドを、
   [辞令文テーブル]から[辞令文]を返すようにする。
 
本質的には、上記の手順と同じ結果を得られるようにしているだけです。
 
引用:
strWhere = "(# & strWhere & #) AND [発令年月日]=" & Me!発令日

strWhere = "(" & strWhere & ") AND [発令年月日]=#" & Me!発令日 & "#"

回答
投稿日時: 21/04/02 11:09:29
投稿者: sk

追記:
 
あと、以下のステートメントも追記された方がよいでしょう。
 

引用:
If 配属 Then strWhere = " OR [種類]='配属'"
If 昇格 Then strWhere = strWhere & " OR [種類]='昇格'"
If 異動 Then strWhere = strWhere & " OR [種類]='異動'"
If strWhere = "" Then Exit Sub

If 配属 Then strWhere = " OR [種類]='配属'"
If 昇格 Then strWhere = strWhere & " OR [種類]='昇格'"
If 異動 Then strWhere = strWhere & " OR [種類]='異動'"
If strWhere = "" Then Exit Sub
strWhere = Mid(strWhere, 5)

投稿日時: 21/04/02 16:06:15
投稿者: MAXBOX

sk様
何度も回答いただき誠にありがとうございます。
 

引用:
本質的には、上記の手順と同じ結果を得られるようにしているだけです。

ご提示頂きありがとうございます。
こちらで試してみます。
 
引用:
strWhere = "(" & strWhere & ") AND [発令年月日]=#" & Me!発令日 & "#"

こちらVBAに入れましたが次は実行時エラー3075で演算子がありませんと出ます。
黄色くなる場所は以前と変わりません。
 
エラーの全文は「クエリ式'('異動')AND[発令年月日]=#2021/04/01#'の構文エラー:演算子がありません」
 
以上になります。
 
宜しくお願い致します。

回答
投稿日時: 21/04/03 09:04:30
投稿者: Suzu

引用:
エラーの全文は「クエリ式'('異動')AND[発令年月日]=#2021/04/01#'の構文エラー:演算子がありません」

 
おそらく、WHERE に指定しようとしている 部分の内容と思われます。
 
基本形構文として、SQL の WHERE句 と同じと考えれば良いです。
   『フィールド名』半角スペース『演算子』半角スペース『比較対象』の構文にならないといけません。
  演算子の前後に半角スペースが必要です。
 
('異動') では、比較対象がなく、SQLとして成立しません。
AND の前後に半角スペースが必要です。
 
 
 
・WHERE が構文として正しいのか
・その WHERE で抽出されるレコードが目的のレコードと一致するのか
を確認する為に、
 
コード中、Docmd.OpenReport の前に
 
Debug.Print strWhere
をいれ、strWhere の内容を イミディエイトウィンドに吐き出させる様にし
 
シングルステップにて実行させ、イミディエイトウィンドに吐き出された strWhere の中身を
 
 
新規クエリ SQLビュー にて
 SELECT * FROM [レポートのレコードソーステーブル/クエリ名] WHERE 『strWhereの中身』
の様にして 選択クエリとして 成立させ 実行し WHERE の内容の確認を行ってみてください

投稿日時: 21/04/07 09:42:53
投稿者: MAXBOX

suzu様
返信が遅くなり申し訳ありません。
 

引用:
コード中、Docmd.OpenReport の前に
 Debug.Print strWhere
をいれ、strWhere の内容を イミディエイトウィンドに吐き出させる様に

 
こちらDebug.Print strWhereを入れて、デバッグしましたがエラー内容がイミディエイトに吐き出されません。
なんの反応もないです・・・
 
以前解決しないままですのでもう少しお付き合い頂けると嬉しいです。

回答
投稿日時: 21/04/07 11:07:03
投稿者: Suzu

引用:
こちらDebug.Print strWhereを入れて、デバッグしましたがエラー内容がイミディエイトに吐き出されません。
なんの反応もないです・・・

 
デバッグは、コードの構文に問題が無い事を確認する処理です。
 
コードを修正し、シングルステップで、Docmd.OpenReport の前まで実行するのです。
その際、直前に Debug.Print strWhere があれば、
その時点での 変数 strWhere の内容がイミディエイトウィンドに吐き出されます。
 
Docmd.OpenReport の WhereCondition引数には、
SQLの WHERE句と同じ構文の内容が入っていなければならないので
SQL の WHERE句に strWhere の内容を入れてみて確認する趣旨です。

回答
投稿日時: 21/04/07 11:57:26
投稿者: sk

bee20 さんの引用:
こちらDebug.Print strWhereを入れて、デバッグしましたが
エラー内容がイミディエイトに吐き出されません。

エラーの内容ではなく、変数の strWhere の値ですね。
 
Suzu さんの引用:
コード中、Docmd.OpenReport の前に

bee20 さんの引用:
If 配属 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_配属", acViewPreview, , strWhere, acDialog

Debug.Print strWhere
If 配属 And DCount("*", "辞令レポートクエリ", strWhere) Then _
DoCmd.OpenReport "辞令_配属", acViewPreview, , strWhere, acDialog
 
------------------------------------------------------------------
 
Debug.Print メソッドを記述するなら上記の辺りで。
 
bee20 さんの引用:
If 異動 Then strWhere = strWhere & " OR [種類]='異動'"

sk さんの引用:
strWhere = Mid(strWhere, 5)

bee20 さんの引用:
エラーの全文は「クエリ式'('異動')AND[発令年月日]=#2021/04/01#'の構文エラー:演算子がありません」

本当に当初のコードの通りであるなら、変数 strWhere の値が
上記のような文字列になることはあり得ません。
 
(フォームモジュール)
---------------------------------------------------------------------
Private Sub Form_Load()
 
    Me![配属] = False
    Me![昇格] = False
    Me![異動] = False
 
End Sub
 
Private Sub 印刷_Click()
 
    Dim strWhere As String
     
    If Me![配属] Then
        strWhere = strWhere & ",'配属'"
    End If
     
    If Me![昇格] Then
        strWhere = strWhere & ",'昇格'"
    End If
     
    If Me![異動] Then
        strWhere = strWhere & ",'異動'"
    End If
     
    If strWhere = "" Then
        MsgBox "異動の種類が指定されていません。", vbExclamation, "入力エラー"
        Exit Sub
    End If
     
    strWhere = "[種類] In (" & Mid(strWhere, 2) & ")"
     
    If Not IsNull(Me!cmb社員番号) Then
        strWhere = strWhere & " AND [社員番号]=" & Me!cmb社員番号
    End If
     
    If IsDate(Me!発令日) Then
        strWhere = strWhere & " AND [発令年月日]=#" & Format(Me!発令日, "yyyy/mm/dd") & "#"
    End If
     
    Debug.Print strWhere
     
    Dim lngCount As Long
    lngCount = DCount("*", "辞令レポートクエリ", strWhere)
    Debug.Print "該当件数: " & lngCount & "件"
    If lngCount = 0 Then
        MsgBox "出力対象となる異動履歴はありません。", vbExclamation, "対象データなし"
        Exit Sub
    End If
     
    If Me![配属] Then
        OpenTransferOrderReport "配属", strWhere
    End If
     
    If Me![昇格] Then
        OpenTransferOrderReport "昇格", strWhere
    End If
     
    If Me![異動] Then
        OpenTransferOrderReport "異動", strWhere
    End If
 
End Sub
 
Private Sub OpenTransferOrderReport(ByVal TransferType As String, Optional ByVal WhereCondition As String)
 
    If TransferType = "" Then
        Exit Sub
    End If
 
    Dim strCriteria As String
    strCriteria = "[種類]='" & TransferType & "'"
    If WhereCondition <> "" Then
        strCriteria = strCriteria & " AND (" & WhereCondition & ")"
    End If
     
    Debug.Print strCriteria
     
    Dim lngCount As Long
    lngCount = DCount("*", "辞令レポートクエリ", strCriteria)
    Debug.Print "該当件数: " & lngCount & "件"
    If lngCount = 0 Then
        Exit Sub
    End If
     
    Dim strReportName As String
    strReportName = "辞令_" & TransferType
    DoCmd.OpenReport strReportName, acViewPreview, , strCriteria
    Debug.Print "レポート[" & strReportName & "]の印刷プレビューを開きました。"
 
End Sub
---------------------------------------------------------------------
 
とりあえず、上記のサンプルのような形であれば
よろしいのではないかと。

投稿日時: 21/04/08 09:40:40
投稿者: MAXBOX

sk様
提示して頂いたコードをもとに作成すると思った通りの仕様ができました!!
本当にありがとうございます。
 
もう少し付け加えたい仕様があるので残りは自力で頑張ってみます!!
本当にありがとうございました。