strSQL = "SELECT 個人データ.氏名,出勤データ.月日 FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan WHERE 出勤データ.jan = '1000000000016' ORDER BY 出勤データ.月日 DESC" '古い順はASC
Set daoRs = daoCn.OpenRecordset(strSQL, dbOpenDynaset) 'ADOレコードセットオブジェクトを作成
If daoRs.RecordCount <> 0 Then
i = 1
Do
daoRs.Edit
daoRs!番号 = i
daoRs.Update
i = i + 1
daoRs.MoveNext
Loop Until daoRs.EOF = Rtrue
End If
daoRs.Close
End Sub
本題は解決しているようですが回答すると、
Group By句は集計の範囲を設定します。対応するHaving句もその範囲内で処理を行います
'Max(出勤データ.月日)'をSELECT句に含めてみてください。各グループ(出力レコード)ごとに、'Max(出勤データ.月日)'フィールドの値が変わるはずです。そのほかのグループ化の設定によっては'Max(出勤データ.月日)'フィールドが一致するレコードも出力されるかもしれません
SELECT TOP 1 個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 AS 月日
FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan
WHERE
個人データ.jan = '1000000000016'
AND 出勤データ.月日 = DMax("月日","出勤データ","jan='1000000000016'")
TOP 1 を使う場合のコード例
SELECT TOP 1 個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 AS 月日
FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan
WHERE 個人データ.jan = '1000000000016'
ORDER BY 出勤データ.月日 DESC;
SELECT 個人データ.氏名,個人データ.住所,出勤データ.時間, Max(出勤データ.月日) FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan GROUP BY 出勤データ.jan,個人データ.氏名,個人データ.住所,出勤データ.時間 HAVING 出勤データ.jan = '1000000000016'
とするとエラーは出ませんが、すべてのデータを取得してしまうので、意味がありません。
SELECT 個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan GROUP BY 出勤データ.jan,個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 HAVING 出勤データ.jan = '1000000000016' and 出勤データ.月日 = Max(出勤データ.月日)
エラーメッセージが謎すぎますよねぇ
元(英語)のエラーメッセージはタブン「You tried to execute a query that does not include the specified expression <name> as part of an aggregate function.」で、Google翻訳かけてさらに意訳すると、「集計関数に<name>が存在しないため、クエリを実行できません」といったところでしょう
書き換えるルールを説明して下さい。3フィールドが複数該当したらどうなるの?
回答の前に、番号について説明をしてほしい。Aさんの8/23の番号1、2、3みたいになるとして、違いは何?
あいまいな値で結合はできないので、交差結合から、フィールドを
Like
比較して更新するレコードのキーと変更後の値のデータを生成し、その後、レコードの更新
の値としてDlookup関数で変換語句を拾い出す更新クエリを作成するとかすれば行けると思います前提の話入れるのすっかり忘れてました
1ページに収まる、または、改ページの制御がないならそのレポートをサブレポートとして埋め込めばいいです
ただ、サブレポートはコントロールなので、その内部ではページの概念がないようです。(情報検索してたらhatenaさんが回答している案件がありました)
ページ表記も同様、ページ表記のための処理はされないのでしょう
ページの概念がないので、ページヘッダーやページフッターをページごとに出力するということもできないと思われます
サマリーの方のページ数が表示されないですね。
データにもよりますが、2~3ページです。
サマリーデータのページ数が表示じされないということでしょうか。
サマリーデータは何ページぐらいになりますか。
hatena様
お世話になります。
ちょっとやってみたのですが、ページフッターでページ数が表示されないのですが、そういうものなのでしょうか?
明細データのレポートヘッダーにサマリーデータをサブレポートしてと埋め込めばどうですか。
私はよくこの方法を使います。
hiroton様
ご返答ありがとうございます。
やはり普通にはできなさそうですね。
popplerを試してみます。
標準機能ではできなさそうなので、PDF出力後にファイル操作するしかないんじゃないですかね
いろいろ方法はあるようですが、popplerは簡単そうでした
読ませていただいて、早速役に立ちました。
SELECT以下の部分に、出勤データ.番号が必要だったのですね。
EXCELL VBAを使ってSQLを動かす情報は、極端に少なくなるので、本当に助かりました。
引き続き、ヒットしたデータを取得してLOOPを抜けるコードを追加してみます。
ありがとう!!!!!
実は、とりあえず連番を振ろうと思い、コードをひとつ書いてみたのですが、
Sub dao()
Dim DB As dao.Database 'Databaseオブジェクトを扱う変数(DB)を宣言
Dim rst As dao.Recordset 'Recordsetオブジェクトを扱う変数(RS)を宣言
Dim strSQL As String
Dim i As Long
strFileName = "出勤 - コピー.accdb"
Set daoCn = DBEngine.Workspaces(0).OpenDatabase("C:\Users\tasuk\Desktop\VBA\経理\出勤\" & strFileName)
jan = "1000000000016"
strSQL = "SELECT 個人データ.氏名,出勤データ.月日 FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan WHERE 出勤データ.jan = '1000000000016' ORDER BY 出勤データ.月日 DESC" '古い順はASC
Set daoRs = daoCn.OpenRecordset(strSQL, dbOpenDynaset) 'ADOレコードセットオブジェクトを作成
If daoRs.RecordCount <> 0 Then
i = 1
Do
daoRs.Edit
daoRs!番号 = i
daoRs.Update
i = i + 1
daoRs.MoveNext
Loop Until daoRs.EOF = Rtrue
End If
daoRs.Close
End Sub
daoRs!番号のところで、このコレクションには項目がありませんのメッセージが、
出勤 - コピー.accdbには、番号のフィールドを追加しておいたのに
ということで、困っていたのです。
さっそく読ませていただきます。
段違いに高速化されるはずです。
自動でDAOを使用して連番をふる汎用関数を下記で紹介してますので、ご参考に。
ありがとうございます。
TOP 5 をDESCで取得して、TOP 1はASCという感じですね。
さっそく、試してみますが、ひとつ気になる事があります。
Dcountなどで、クエリでカウントしようとすると、データによってはドッコイショという感じになるのです。
サブクエリを使っても同じ感じです。
なので、DAOで日付を降順で連番をふりつつ、
ターゲットになる順位がでてきたら、LOOPを抜けるようにした方が効率的なのかと思ってコードを書き始めたのですが、
DAOは、省エネにつながるのでしょうか?
ACCESSはよく分からないので、EXCELLにしがみついている状態なのですが、
最近EXCELLから離れろという幻聴が聞こえる回数が増えてきて、
尻込みしております。
回答ありがとうございます!
移行期間として更新の必要がある住所録データは今までのExcelファイルを使いたかったので、この方法が一番いいです。
作成段階で絶対につまづくと思うので、その時にはまたよろしくお願いします。
TOP 1 で1番目のレコードを取得する方法は既に回答してますので、それの応用で、
例えば5番目のレコードを取得するなら、TOP 5 で上位5番目までのレコードを取得するSQLを記述して、
それをサブクエリにして Top 1 で1番目を取得するようにすればいいでしょう。
おかげさまで、解決いたしました。
現在、〇番目のデータを取得する方法に取り組んでいます。
一度、EXCELに書き出してしまえば造作もないことなのですが、それは避けたいと思っております。
解決できなかったら、またお願い致します。
本題は解決しているようですが回答すると、
Group By句は集計の範囲を設定します。対応するHaving句もその範囲内で処理を行います
'Max(出勤データ.月日)'をSELECT句に含めてみてください。各グループ(出力レコード)ごとに、'Max(出勤データ.月日)'フィールドの値が変わるはずです。そのほかのグループ化の設定によっては'Max(出勤データ.月日)'フィールドが一致するレコードも出力されるかもしれません
いずれにせよ、月日でグループ化したデータで月日の最大値をとっても、それは常に同じ値になり、
出勤データ.月日 = Max(出勤データ.月日)
は月日がNULLでない限り常にTrue
になりますあと、最初の質問
については解決したということでよろしいのでしょうか。
最初の質問、クエリで下記をしたい
途中から、VBAの話になって、
今度は、集計についての質問。
話がどんどんとんでいって、こちらから見たらなんのことか、という状態です。
別質問なら、新規投稿で内容を詳細に説明して質問してください。
セルのデータをテーブルとしてリンクすることができます。
このリンクテーブルをもとにフォームやレポートを作ればいいでしょう。
リンクテーブルだと更新できないので まずは 閲覧(フォーム)と印刷(レポート)部分から作成するといいでしょう。
その間はエクセル側でデータ更新します。
ある程度できたらリンクテーブルは削除して、エクセルデータをテーブルとしてインポートします。
それ以後はアクセス側でデータ更新します。
ざつとこんな感じで移行することになります。
ただエクセルデータがデータベースとして扱える形になっていることが前提です。
追加の質問で申し訳ないです。
今、思いついたのですが、個人データに在職のフィールドを用意しておけば、
GROUP BYで在職をグループ化して、一括でデータを集計する事が可能になるのでしょうか?
おさわがせしました。
タイプミスでした。
hatenaさんはじめ、有難うございました。
Excelワークシート関数かもしれないので、WorksheetFunction.を試してみましたが、
型が一致しませんになりました。
月日は、ACCESSに日付/時刻型で登録してあります。
Max関数が、VBAのコード内では使用できないことは分かりました。
ところが、Dmaxでもmaxでも、
Sub または Function が定義されていません。
と表示されて、先に進みません。
単純に
Dim myMax As Variant
myMax = DMax("月日", "出勤データ", "jan='1000000000016'")
MsgBox myMax
としても、同じエラーが出ます。
EXCEL2016で、Ofiice 16.0 objectと、Active X 6.1はには、チェックが入っている状態です。
何故なのでしょうか?
hirotonさんから回答がある通り、集計関数(Max)を使う場合は、すべてのフィールドに対して、集計の指定をするか、グループ化する必要があります。それがしてないのでエラーになりますね。
この要件なら、サブクエリかDMax関数で月日の最大を取得してそれを抽出条件にするか、月日で降順に並べ替えて先頭レコード(TOP 1)を取得することになります。
DMax関数を使う場合のコード例
TOP 1 を使う場合のコード例
jan = '1000000000016' and 出勤データ.月日 = Max(出勤データ.月日)は、1件しかデータが無いはずだと思うのですが
SELECT 個人データ.氏名,個人データ.住所,出勤データ.時間, Max(出勤データ.月日) FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan GROUP BY 出勤データ.jan,個人データ.氏名,個人データ.住所,出勤データ.時間 HAVING 出勤データ.jan = '1000000000016'
とするとエラーは出ませんが、すべてのデータを取得してしまうので、意味がありません。
SELECT 個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 FROM 個人データ INNER JOIN 出勤データ ON 個人データ.jan=出勤データ.jan GROUP BY 出勤データ.jan,個人データ.氏名,個人データ.住所,出勤データ.時間, 出勤データ.月日 HAVING 出勤データ.jan = '1000000000016' and 出勤データ.月日 = Max(出勤データ.月日)
としてみても、エラーは出ませんが全データを取得してしまいます。
どうしたら、よいのでしょうか?
クエリのデザインビューで目的のクエリを作成して、SQLビューに切り替えて確認してみるといいですよ
エラーメッセージが謎すぎますよねぇ
元(英語)のエラーメッセージはタブン「You tried to execute a query that does not include the specified expression
<name>
as part of an aggregate function.」で、Google翻訳かけてさらに意訳すると、「集計関数に<name>
が存在しないため、クエリを実行できません」といったところでしょうクエリで集計を行う場合、出力する全てのフィールドで何らかの集計の指定、またはグループ化の指定が必要になります
問題のクエリはグループ化の指定がないため、「氏名」を何らかの集計方法だとして処理しようとして「『氏名』という集計方法はないですよ」とエラーを出しているわけです
これです、これです。
どうもありがとうございました。
BuildCriteriaメソッドのことでしょうか。
Application.BuildCriteria メソッド (Access) | Microsoft Learn
hatenaさん、返信ありがとうございます。
クエリの条件式をVBAで作成したいのですが、条件式を生成する関数(?)があったような薄い記憶があるのですが、思い出せません。
ぼんやりしすぎです。
もう少し具体的に説明してもらえませんか。
どこでどのように使いたいのか。
VBAなのか、コントロールソースなのか、クエリなのか、、、、
hatenaさん hirotonさん ありがとうございます。
どうしてもエラーになってしまうので、今回は出力までの期間が短い為、そもそもの時間表示を90分、120分等とすることにしました。
ただ、コントロールソースでの関数で表記の変更が可能ということがわかったので、
次回の更新時に向けてゆっくり勉強していってみようと思います。
ありがとうございました。
00分
を消すだけならでいいんじゃないかな
Replace 関数
ありがとうございます。データ型はテキストです。
テキストのまま
=Format([休憩時間],IIf([休憩時間]=0,"h時間","h時間nn分")
のようにしたら、#Type!と出てしまいました。。
ご対応ありがとうございます。
とても参考になりました。実際に設定してみます。
休憩時間フィールドのデータ型は、日付/時刻型でしょうか。
だとしたら、レポート上のテキストボックスのコントロールソースを下記のように設定すればいいでしょう。
※コードに間違いがあったので修正しました。
コンボボックスの値集合ソースをクエリにして、抽出条件で他のコンボボックスの値を除去するようにすればいいでしょう。
さらに、VBAかマクロでコンボボックスのフォーカス取得時に自身を再クエリするようにします。
例えば、コンボ1、コンボ2、コンボ3 とあって、
リストに、テーブル1 の フィールド1 のデータが表示されているとして、
コンボ1の値集合ソースを下記のように設定します。
フォーカス取得時のイベントプロシージャに下記のコードを記述
コンボ2、コンボ3 も同様に設定します。
hiroton様
なるほど「数字」に限定して抽出するように関数を考えれば、私でも関数でできそうな気がします。
VBA一つずつ勉強してみます。いろいろ、考えて下さりありがとうございました。