Access (VBA)

Access VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 7 Professional : Access 2000)
日にちのチェックが何番目入っているか調べたい
投稿日時: 19/01/24 22:57:30
投稿者: 浦島太郎

出席簿テーブルに1日〜31日をYes/No型で作っております。何日と何日にチェックが入っているか調べたいのです。例えば5日、9日、15日、20日...にチェックが入ってあれば5日が1番目、9日が2番目等々、日にちと何番目かをVBAで調べたいのですがテーブルやクエリは横並びですのでなかなか上手く行きません。何方かご教授頂ければ有り難いです。

回答
投稿日時: 19/01/25 07:42:53
投稿者: Suzu

テーブル構造が
 

フィールド名	データ型
 1日	Yes/No
 2日	Yes/No
  :	 :
30日	Yes/No
31日	Yes/No

となっているのでしょうか?
 
 
フィールド名	データ型
日付	数値型
flg	Yes/No

としてはいかがですか?
 
そうすれば
【クエリで値(成績・実績・記録等)に順位をつける】
https://www.moug.net/tech/acopr/0040028.html
 
【クエリで順位を計算する】
https://www.moug.net/tech/acopr/0040034.html
 
の様に クエリで取得できますから VBAは不要になりますよ。
 
サブクエリを使用するなら 下記の感じでしょうか。
 
SELECT
  TB.日付,
  (
    SELECT COUNT(Tmp.日付) AS 順
    FROM テーブル名 AS Tmp
    WHERE Tmp.日付<=TB.日付
  ) AS 順位
FROM テーブル名 AS TB
 
 
どうしてもテーブル構造をそのままで行う必要があるなら
レコードセットを取得し、レコードセットのフィールドコレクションに対し
 
For i = 0 To rs.Fields.Count -1
 If rs.Fields(i) = True Then
  j = j +1
  MsgBox rs.Fields(i).Name & " : " & j
 End If
Next
 
の様な方法で取得する事になるでしょう。

投稿日時: 19/02/18 20:36:03
投稿者: 浦島太郎

Suzuさん 返事が大変遅くなり申し訳ございません。それに 素早い回答有り難うございました。
 
>>どうしてもテーブル構造をそのままで行う必要があるなら
>>レコードセットを取得し、レコードセットのフィールドコレクションに対し
 
フィールド名はいろんな所で使ってますので変えるのは難しく思いますので
テーブル作成して、レコードセットの方でやってみました。
 
下記の様にやってみましたが、プレビュー画面で最初の生徒さんは上手く行きました。次の生徒さんに移動した時、前の人と同じ日にちになってしまいます。3人目も最初の人と同じ日にちでした。
Suzuさんが出してくれてたMsgBOXだけのコードでも同じでした。(ですので、.出席日1 等 初期化してみましたが) その他色々やってみましたが、どうしても解決できません。ご教授願えたら有り難いです。
Access2000 DOA 3.6  単票です
 
Private Sub 詳細_Print(Cancel As Integer, PrintCount As Integer)
Dim db As Database
Dim rst As Recordset
Dim i, j, n, m As Integer
 
Set db = CurrentDb
Set rst = db.OpenRecordset("出席日")
 
 With CodeContextObject
  
.出席日1 = "": .出席日2 = "": .出席日3 = "": .出席日4 = "": ・・・・・・・: .出席日29 = "": .出席日30 = "": .出席日31 = ""
  
For i = 0 To rst.Fields.Count - 1
 If rst.Fields(i) = True Then
  j = j + 1
   
  If j = 1 Then
     .出席日1 = rst.Fields(i).Name
  End If
   
  If j = 2 Then
     .出席日2 = rst.Fields(i).Name
  End If
 
  If j = 3 Then
     .出席日3 = rst.Fields(i).Name
  End If
   
  If j = 4 Then
     .出席日4 = rst.Fields(i).Name
  End If
       ・
       ・
       ・
       ・
       ・
  If j = 29 Then
     .出席日29 = rst.Fields(i).Name
  End If
 
  If j = 30 Then
     .出席日30 = rst.Fields(i).Name
  End If
  
  If j = 31 Then
     .出席日31 = rst.Fields(i).Name
  End If
 
 End If
Next i
 
 End With
 
 rst.Close: Set rst = Nothing
 db.Close: Set db = Nothing
 
End Sub

回答
投稿日時: 19/02/18 22:56:35
投稿者: Suzu

引用:
最初の生徒さんは上手く行きました。次の生徒さんに移動した時、前の人と同じ日にちになってしまいます。

引用:
フィールド名はいろんな所で使ってますので変えるのは難しく思いますので
テーブル作成して、レコードセットの方でやってみました。

 
生徒さん??
初めての話ですよね?
 
どんな構造のテーブルを作成し試されたのでしょう?
 
また、最終的にどんな出力を希望されているのでしょうか?
 
得たい出力が
 
学籍番号	氏名	1日	2日	3日	・・・	28日	29日	30日	31日
00001	鈴木太郎	レ	レ	_	・・・	レ	レ	レ	_
00002	山田花子	レ	レ	レ	・・・	_	レ	レ	レ
	:

の様な形だとは思うのですが、
 
テーブル「出勤簿」の構造が
フィールド名	データ型
 1日	Yes/No
 2日	Yes/No
  :	 :
30日	Yes/No
31日	Yes/No

であれば、学籍番号との関連づけは何もありませんよね?
 
 
少なくとも
フィールド名	データ型
学籍番号	テキスト型
 1日	Yes/No
 2日	Yes/No
  :	 :
30日	Yes/No
31日	Yes/No

の様にしなくてはならないのでは?
 
でも。。上記の構造だとして。。
月が替わったら全レコード消すのですか?
年月も考えるなら
 
フィールド名	データ型
学籍番号	テキスト型
年月	長整数型
 1日	Yes/No
 2日	Yes/No
  :	 :
30日	Yes/No
31日	Yes/No

の様になるのでは?
 
 
でも、
データベースとして考えたとき、
上記テーブル構造で、
 
2019年2月18日 は レ なのか 空白なのか
とか
2019年2月の は レ の数 の合計
 
を計算する必要性が発生しませんか?
その場合の計算はすごく手間ではありませんか?
 
今現在、どんな出力が欲しい だけではなく
将来を見据えたテーブル構造にした方が良いと思いますよ。
 
出欠のみで良いと言うなら
 
フィールド名    データ型
学籍番号    テキスト型
日付    日付/時刻型
出欠    バイト型(出席:1、欠席:0)
 
の様にしますかね。。
 
横方向日付を並べたいなら、
そのテーブルに対しクロス集計クエリを使います。
 
https://support.office.com/ja-jp/article/%E3%82%AF%E3%83%AD%E3%82%B9%E9%9B%86%E8%A8%88%E3%82%AF%E3%82%A8%E3%83%AA%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E9%9B%86%E8%A8%88%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E8%AA%AD%E3%81%BF%E3%82%84%E3%81%99%E3%81%8F%E3%81%99%E3%82%8B-8465b89c-2ff2-4cc8-ba60-2cd8484667e8

回答
投稿日時: 19/02/19 10:25:02
投稿者: Suzu

自分で書き込んでおいて申し訳ありませんが、クロス集計云々は忘れてください。
 
まず

引用:
どんな構造のテーブルを作成し試されたのでしょう?
  
また、最終的にどんな出力を希望されているのでしょうか?

これらについて、教えてください。

投稿日時: 19/02/20 01:22:46
投稿者: 浦島太郎

Suzuさん 早速の返事有り難うございます
 
元データテーブルの所からフリガナ昇順  請求月 請求金額<>0 を非表示にして抽出し、名前と1日〜31日(Yes/No型)だけのデータをテーブル作成クエリで作りました
実際には For i = 1 To rst.Fields.Count - 2 です。
If rst.Fields(i) = True Then が True なのでYes/No型のままです。
 
尚作成テーブルはその月ごとで有ればいいので元データテーブルにデータは有りますので消えてもいいですし、出席合計日数などは出来てますので、Suzuさんの御懸念有り難うございます。
 
欲しいデータは単票レポートの 
出席日とういう項目の所に、私の最初の質問の所の例としましたら
 
レポートに
 
1行目の 非連結の出席日1の所に 5日
2行目の 非連結の出席日2の所に 9日
3行目の 非連結の出席日3の所に 15日
4行目の 非連結の出席日4の所に 20日 とだけ入ればいいのです。
 
レポートプレビューで次の生徒さんに移った時はその生徒さんの出席日が10日と22日で有れば
 
1行目の 非連結の出席日1の所に 10日
2行目の 非連結の出席日2の所に 22日 と入ればいいのです。
 
実際には項目の出席日31迄は必要無いですけどね 出席日20 まで有れば十分です。
次の人に移った時前の人のデータではなく次の人のデータで有ればいいのです。
よろしくお願いします。
 

回答
投稿日時: 19/02/20 10:09:22
投稿者: Suzu

テーブルは、

引用:
名前と1日〜31日(Yes/No型)だけのデータをテーブル作成クエリで作りました

 
フィールド名    データ型
-------------------------
名前    テキスト型
1    Yes/No
2    Yes/No
:    :
30    Yes/No
31    Yes/No
 
こうなっているのですよね?
 
そのうえで 1人目の生徒のレポートが
 
引用:
1行目の 非連結の出席日1の所に 5日
2行目の 非連結の出席日2の所に 9日
3行目の 非連結の出席日3の所に 15日
4行目の 非連結の出席日4の所に 20日 とだけ入ればいいのです。

 
こうなるためには、
非連結でなくて、連結にしてしまって
レポートのレコードソースの、1人目のレコードを4行作った方が楽です。
 
また、
引用:

レポートプレビューで次の生徒さんに移った時はその生徒さんの出席日が10日と22日で有れば
  
1行目の 非連結の出席日1の所に 10日
2行目の 非連結の出席日2の所に 22日 と入ればいいのです。

 
この部分も、
レポートのレコードソースの、2人目のレコードを2行作った方が楽です。
 
 
あくまで非連結で行いたいなら
NextRecord,PrintSection,MoveLayout を調べてみてください。

投稿日時: 19/02/21 02:07:45
投稿者: 浦島太郎

Suzuさん 早速の返事有り難うございます
 

引用:

フィールド名 データ型
-------------------------
名前 テキスト型
1 Yes/No
2 Yes/No
: :
30 Yes/No
31 Yes/No
こうなっているのですよね?

はい そうです
 
引用:

こうなるためには、
非連結でなくて、連結にしてしまって
レポートのレコードソースの、1人目のレコードを4行作った方が楽です。

 
正にこのデータ構造で、連結で行けたら良いのですが、それが出来なかったので こちらで質問させて頂いたわけです。
 
 
引用:

 
この部分も、
レポートのレコードソースの、2人目のレコードを2行作った方が楽です。
 
あくまで非連結で行いたいなら
NextRecord,PrintSection,MoveLayout を調べてみてください。

レポートの詳細の印刷時のイベントに書いた For Next のコードが次のページ移動した時どうして働かないのでしょうか? 改ページの所も試して見ましたが変化は有りませんでした。もう少し御教授お願いします。
 

回答
投稿日時: 19/02/21 11:39:00
投稿者: Suzu

現状の、テーブル「出勤簿」から、

引用:
レポートのレコードソースの、1人目のレコードを4行作った方が楽です。

を行うためのレコードを作成するためには、
 
1. 出勤簿をコピー
2. 出勤簿2を作成し、出勤簿2のレコードを削除
3. そのうえで、追加クエリを 31回実行
    INSERT INTO 出勤簿2 ([名前], [1日])
    SELECT [名前], [1日] FROM 出勤簿 WHERE [1日] = TRUE
 
    INSERT INTO 出勤簿2 ([名前], [2日])
    SELECT [名前], [2日] FROM 出勤簿 WHERE [2日] = TRUE
       :
    INSERT INTO 出勤簿2 ([名前], [31日])
    SELECT [名前], [31日] FROM 出勤簿 WHERE [31日] = TRUE
 
VBA DAOなら
 
 
Sub sumple()
  Dim db As DAO.Database
  Dim i As Long
  Dim strSQL As String
   
  Set db = CurrentDb
  For i = 1 To 31
    strSQL = "INSERT INTO 出勤簿2 ([名前], [" & StrConv(i, vbWide) & "]) " & _
             "SELECT [名前], [" & StrConv(i, vbWide) & "日] FROM 出勤簿 WHERE [" & StrConv(i, vbWide) & "日] = TRUE"
    db.Execute strSQL
  Next
End Sub
の様な感じで良いのでは?
 
でも、そもそも、出勤簿 のレコードを作成するときに そうなるようにしておく方が簡単かもしれませんね。
この詳細な方法は、テーブル出勤簿の作成方法が判らないので、これ以上は控えます。
(提示されたとしても、作成方法まではご教示しかねます。)
 
 
引用:
レポートの詳細の印刷時のイベントに書いた For Next のコードが次のページ移動した時どうして働かないのでしょうか? 

 
動作しています。
レコードソースが、3レコードしかなければ、
レポートには、3行のデータしか出てきません。
 
そこを、何行もでてくる様に(みせる)のが、NextRecord,PrintSection,MoveLayout です。
それらの操作をしないかぎり、レコードソースが3レコードなら、3行しか表示されないのは当然です。

回答
投稿日時: 19/02/21 11:56:06
投稿者: hatena
投稿者のウェブサイトに移動

引用:
フィールド名 データ型
-------------------------
名前 テキスト型
1 Yes/No
2 Yes/No
: :
30 Yes/No
31 Yes/No
こうなっているのですよね?
 
はい そうです

  
データの持ち方は再検討する必要があると思いますが、それはスルーして、
  
レポートの詳細セクションに、横に長いテキストボックスを配置して、
そのコントロールソースを下記のように設定すればどうでしょうか。
  
=Format([1],"; 1日 ") & Format([2],"; 2日 ") & Format([3],"; 3日 ") & ・・・・・
Format([30],";30日 ") & Format([31],";31日 ")
  
フォントは等幅フォントにしないとずれますが。

トピックに返信