SELECT
Qクロス結合.[リマインダーID], Qクロス結合.[リマインダー内容], Qクロス結合.日付, Qクロス結合.曜日,
IIf( [曜日番号合計] = 0, 0, [曜日番号] ) AS 曜日条件,
IIf( [週番号合計] = 0, 0, [週番号] ) AS 週条件
FROM
Qクロス結合 LEFT JOIN ( SELECT [リマインダーID], sum(曜日番号) AS 曜日番号合計, sum(週番号) AS 週番号合計 FROM T条件 GROUP BY [リマインダーID] ) AS 番号合計 ON Qクロス結合.[リマインダーID] = 番号合計.[リマインダーID]
WHERE
( ( ( IIf( [曜日番号合計] = 0, 0, [曜日番号] ) ) In ( select 曜日番号 from T条件 where T条件.リマインダーID = Qクロス結合.リマインダーID ) )
AND ( ( IIf( [週番号合計] = 0, 0, [週番号] ) ) In ( select 週番号 from T条件 where T条件.リマインダーID = Qクロス結合.リマインダーID ) ) )
ORDER BY
Qクロス結合.[リマインダーID],
Qクロス結合.日付;
SELECT x.リマインダーID
, z.日付
, y.曜日番号
, y.週番号
FROM
(
SELECT リマインダーID
FROM T条件
GROUP BY リマインダーID
HAVING Sum( 週番号 ) = 0
OR Sum( 曜日番号 ) = 0
)
x
, T条件 y
, T日付 z
WHERE x.リマインダーID = y.リマインダーID
AND (
y.曜日番号 = Weekday( z.日付 )
OR
y.週番号 = ( Day( z.日付 ) + 6 ) \ 7
)
ORDER BY 1, 2 ;
Public Function 月初(申請日 As Variant) As Variant
If IsNull(申請日) Then Exit Function
'申請日がNULLなら関数は終わり
月初 = DateSerial(Year([申請日]), Month([申請日]) + 1, 1)
'月初めが出る
Do
Select Case Weekday(月初)
Case vbMonday To vbFriday
If IsNull(DLookup("祝日名", "T_祝日", "日付=#" & 許可日 & "#")) Then
Exit Do
End If
End Select
月初 = 月初 + 1
Loop
' 月初めが月曜から金曜の間で祝祭日がNULLならD0文が修了。土日はNULLじゃないから終了しない
終了するまで月初に1日プラスする。
End Function
Public Function 月初(申請日 As Variant) As Variant
If IsNull(申請日) Then Exit Function
月初 = DateSerial(Year([申請日]),Month([申請日])+1,1)
Do
Select Case Weekday(月初)
Case vbMonday To vbFriday
If IsNull(DLookup("祝日名", "T_祝日", "日付=#" & 許可日 & "#")) Then
Exit Do
End If
End Select
月初 = 月初 + 1
Loop
End Function
グループレベル1ヘッダーにコントロールを作成できました。
ありがとうございました。
CreateGroupLevelメソッドの存在は知りませんでした。
さっそく試してみようと思います。
ありがとうございました。
下記が参考になりませんか。フォームでの場合ですが、レポートでも同様な方法で可能です。
列数が変化するクロス集計クエリと連結するフォーム - hatena chips
列数が変化するクロス集計クエリと連結するフォーム - hatena chips
お勧めはしませんが、どうしてもVBAでグループヘッダーを追加したいという場合は、下記が参考になるかと。
CreateGroupLevel メソッド (Access) | Microsoft Docs
VBAでする理由:
・グロス集計したレコードセットを元にレポートを作成しますので、列見出しが変わります。手作業では大変なのでVBAで作成したいのです。
目的:
・プロジェクトの分析(プロパティ値の表示)
今、自分のプロジェクトのフィールドのプロパティ値、コトントロールのプロパティ値を一覧表にしようとしています。
その時、フィールド名が行見出し、プロパティ名が列見出し、プロパティ値が値になるように、クロス集計しています。
そして、グループレベル1にオブジェクト名を表示させたいのです。
レポートではページヘッダーにプロパティ名を縦長で1行に表示させていますが、とても全部を表示させることはできませんので、重要なプロパティ値、値に変更を加えたプロパティ値のみ表示させています。
この列見出しとしているプロパティ名がプロジェクト毎に変わるので、VBAでレポートを作成したいのです。
ここまではできているのですが、グループレベル1ヘッダーにコントロールを作成できれば、完璧だと思うのです。
よろしくお願いします。
デザインビューでグループヘッダーを追加したり、コントロールを追加するのではなくて、VBAでする理由と目的はなんでしょうか。
事前に追加しておいて、必要に応じてVBAで表示/表示をコントロールするほうがはるかに楽ですし、デザインビューで開く必要がないので安全です。
mayuさん
テーブル設計を見直したサンプルのご提示ありがとうございます。
素朴な質問のつもりでしたが、ここまで懇切丁寧に回答いただき、
情報量にただただ圧倒される次第です。
また、その前段にてmayuさんよりご提示いただいた、
SUM集計関数を用いて元のクエリで抽出できなかったレコードを一括で抽出し
別途対処するというアイディアを参考にして下のクエリを作成しました。
こちらで一応望む結果を得ることができましたので、あまりスマートな方法では
ないと自覚していますが、ひとまずこの質問は解決にしようと思います。
以上、大変参考になるご回答数々いただき感謝致します。ありがとうございました。
※ 続き
結果 ( 一部抜粋 )
※ 続き
データ例
< T_リマインダー >
リマインダーの種別において
・ 日 単位で発生するもの は 1 を入力
・ それ以外のもの ( 週・曜日 ) は 2 を入力
というルールにします
< T_条件 >
F1 ---> 条件ID F5 ---> 週番号_from
F2 ---> リマインダーID F6 ---> 週番号_to
F3 ---> 対象月_from F7 ---> 曜日番号_from
F4 ---> 対象月_to F8 ---> 曜日番号_to
F9 ---> 日番号
※2
月、週、曜日において
連続した値( 毎月、毎週、火~金、4月~6月 など )は
連続した範囲として1行で表現し、
連続しない場合は行を分け、データを個別に登録します。
この部分が、データ登録における一番の難関だと思いますが
データサンプルをよくご覧になれば、構造を理解できるでしょう。
※3
日単位で発生するリマインダにおいて
日番号フィールドに入力する値は、月末は 0
それ以外は 日の数字
※4
曜日や週単位で発生するリマインダにおいて
日番号フィールドに入力する値は 0
テーブルの構造を変更する場合のサンプルを以下に載せておきます。
まず、リマインダーは
・ 日 単位で発生するもの
・ それ以外のもの( 週・曜日 )
の2種に大別できるでしょう。
( 両立しない条件のため )
よって、リマインダの定義テーブルに
種別を管理するフィールドが必要になります。( ※1 )
次に、リマインダーの発生周期は
月、週、曜日、日の組み合わせによることから
条件テーブルに、これらの値を格納するフィールドが必要 ( ※2 )
条件テーブルへデータを登録するにあたり、
行数が増えることに漠然とした不安を感じておられるようなので
行数を抑制できるフィールド構成にします ( ※3 )
特定の日に1度きりで実施されるリマインダと
特定の周期で何度も実施されるリマインダは
入力項目を共通化して統一し、Nullや意味不明の値は許可しない ( ※4 )
※1 ~ ※4 を網羅したテーブル定義
mayuさん
大変に熱のこもったご回答をいただきありがとうございます。
ひとまず、中段にご提示いただいた、元のクエリで抽出されないレコードを集計クエリで別途抽出しユニオンクエリで結合するという考え方を参考にさせていただき、
実際の動作を検証してみたいと思います。
また、独学なため実例を見る機会があまりなく、テーブル設計含めより適した方法を引き続き検討していきたいと思いますので、機会がありましたらぜひよろしくお願い致します。以上、ありがとうございました。
「月」や「日付」の条件をテーブルに追加して長大になるというのは
意味がわかりかねます。
前回の回答で、私はフィールド構成の変更を提案したわけではなく
データの持ち方を変更するよう、示唆したに過ぎません。
したがって、ご自身が考える「 長大にならない 」設計方針と
「月」や「日付」をどのような構成でデータ登録し、
週次や曜日毎に実施するデータと同居させる予定なのか
また、どのような SQL で抽出を行うつもりでいるのか、構想をお聞かせ願えますか。
現状の構成は、以下の問題点が明白ですので
・ 第三者から見て、単一の行からテーブルのデータ構造が把握できない
・ 相関サブクエリというのは、莫大な演算回数が発生するパフォーマンスの悪い SQL である
・ 複雑なサブクエリを複数回発行しても、思ったようにデータが抽出できていない
・ 演算フィールドを左辺に指定して抽出条件を指定しているため、インデックスが効かない
運用も構築も この先 地獄を見る覚悟がおありということでしたら
一応、ご希望の回答はしておきます。
なお、週番号だけを指定するリマインダーが あるのかどうか不明ですが
とりあえず、どちらでもいいように冗長な SQL にしておきます。
以下の結果を ユニオンクエリで rookjimさん記載の SQL と結合すればいいでしょう。
具体的なアドバイスをご希望なら、まずは データベースソフトの扱いにおいて
rookjimさんの方針や考え方は、順番や方向性が真逆である
ということを理解いただかない限り、不毛なやりとりになるでしょう。
のではなく、構築手順は
1. 条件を網羅した適切な構造のテーブルを設計する
2. パフォーマンスや見通しの良い SQL を考える
3. VBAの利用やコントロールの配置は必要最小限に抑え、
シンプルで保守性の高いインターフェース( フォーム・レポート )の構築を目指す
になります。
添付画像における リマインダーID: 1 の内容においても
発生条件が「 第2、第4土曜日 」ですから
フォーム上で [ 指定日 ] [ 日 ] といった項目を ユーザが指定する必要は無いように思いますが
代替値を入力しない限り、テーブル上でそれらの項目は Null になります。
これらの項目を SQLでどう扱うか、見通しが立っていないのでしたら
テーブルの設計から見直す必要があり、当然、フォームも改変を余儀なくされます。
まずは、テーブル設計からやり直す気が有るのか否か、意思表示をお願いします。
mayuさん
つたない質問内容を読み取っていただき、丁寧な回答いただきありがとうございます。
ご指摘いただき、T条件のテーブルの記述の仕方が、望む抽出結果を得るために適さない形式であることがわかりました。
T条件のテーブルが1レコードごとに1条件の構成になっている理由は、ユーザーがくり返し条件を入力するためのフォームを下のように作成したためです。
ご回答いただいたように複数の条件を全て網羅するようにテーブル構成を変更すると、
「月」、「日付」等の並列する条件を追加した際に条件テーブルが長大なものになってしまうため➀については現在のテーブル構成のまま目的の抽出結果を得られる方法を求めております。引き続きご教授いただけますと幸いです。
または
・条件を網羅したテーブルのデータが作成できるようにフォームを再設計する
・T条件のデータを複数の条件を全て網羅するように変換するようクエリを作成する
等で解決できるかと思うのですが、こちらについても具体的な方法をアドバイスいただけますと幸いです。
検討いただき大変有り難く思っております。大変わがままな質問で恐縮ですが
何卒宜しくお願いします。
質問内容 1, 2 両方ともに関連することですが
Tくり返し条件 テーブルの
データ構成に問題があるでしょう。
一意のリマインダーIDを構成する要素は
週番号 + 曜日番号
なのですから
週番号だけ とか、曜日番号だけ という
どちらか1つだけを表現した行を作ってはならないのです。
rookjimさんの例で申し上げるなら
リマインダーID:3 の「 毎週月曜と金曜 」というのは
・ 週番号は 1 または 2 または 3 または 4 または 5
且つ
・ 曜日番号は 2 または 6
であるのに
週番号の入力値を 0 という非該当の数字で表現していることが
SQL文が複雑になり、思ったように抽出できない原因になっています。
T条件
このように
複数の条件( 週 + 曜日 )を全て網羅するようなデータ構成に変更すると
SQL文は以下のように簡潔に記述できて
抽出漏れも解消できます。
質問者です。
テーブルの名前は
Tくり返し条件× → T条件○
でした。
大変失礼致しました。
よろしくお願い致します。
hatena様、本当にありがとうございます。
思いもよらいな現象でビックリしています。
ありがとう御座いました。
下記の設定でどうでしょうか。
値集合ソース
連結列: 1
列数: 3
列幅: 0cm;0.002cm
解説
コンボボックスのボックス部に表示されるのは、列幅0cm以外の最初の列
上記の場合は、2列目がボックス部に表示される。
2列目は列幅が0.002cmなので存在はするがリストではほぼ見えない状態。
リストには3列から表示されてるように見える。
すいません。
選択後にインデントの表示になってるいるので表示がずれてしまいます。
書式か何かで空白のインデント分を調整出来ますでしょうか?
…凄いです。
目からうろこです!!!!!
ツリービューは設定が大変なので本当に助かります。
ありがとうございます。!!
飲食店でしょうか。質問が曖昧過ぎるので具体的に回答はむずかしいです。
Accessはまったくの初めてですか。
だとしたら、まずは、入門書か入門サイトで基本を学習してからでないと難しいと思います。
まずは、テーブル設計から始めてみてください。
下記がテーブル設計については詳しく解説しています。
インデントでいいのなら、通常のコンボボックスで、先頭に空白をいれればいいように思います。
例えば、リストのもとになるテーブル設計を下記のようにしておいて、
テーブル1
さらに下記のように設定すれば、
連結列:1
列数:2
列幅:0cm
疑似階層表示になると思います。
あ、階層表示といっても、インデント!?というのでしょうか、
それが設定出来るので、疑似階層表示といえば良いのかも知れません。
やはりそうですか。
コードが短く済むのでいいかなと思ったのですが、
見たところリスト行数の設定も難しそうですし、
keyの設定も、数字を文字列(全角にしても)に変換してもエラーが出ますし…
TreeViewコントロールで実装する事にします。
ありがとうございました。
イメージコンボボックスって階層表示に対応してるんですか?
階層表示するなら、自分なら、TreeViewコントロールをボタンのクリックで表示/非表示させる方針で行くかな?
Office TANAKA - TreeViewコントロールの使い方
返信ありがとうございます。
階層表示にしたいのでイメージコンボボックスをと考えていました。
色々とググったのですが、詳細が記載されているところが見当たらなくて。
イメージコンボボックスは使ったことがないのでご質問に回答できないですが、
普通のコンボボックスではダメなんですか?
hatenaさま、返信ありがとうございます。
日が変わり脳みそがリセットされたら、解決いたしました。
>一時テーブルへデータをエクスポートするときの抽出条件はどこでどのように設定してますか。
抽出条件に関する「W.回数=T.回数」について、
DELETEのSQLでの記載箇所“どこで”を誤っておりました。
EXSITSの中でこねくり回してしまっておりました。
下記のとおり書いたらうまく動作しました。
DELETE FROM T_受講受付 AS T
WHERE W.回数=T.回数 and NOT EXSITS (SELECT * FROM W_受講受付 AS T WHERE W.申込者=T.申込者)
どうもお騒がせいたしました。
もう不要ではありますが、うまく動作している方のSQLは下記のとおりとしておりました。
(実際のテーブルのフィールドは多いのでstrとしています。)
UPDATE T
INNER JOIN W
ON T.回数=W.回数
SET & strフィールド &
WHERE T.回数= str抽出した回数
INSERT INTO T ( & strフィールド & )
SELECT & strフィールド &
FROM W
ありがとうございました。
今後ともよろしくお願いいたしますm(__)m
とりあえず画像ファイルからの想像ですが、
一時テーブル以外のレコードがすべて削除されているようですね。
データを一時テーブルへ転送するときに、元テーブルに何らかの抽出条件を設定しているはずです。
削除クエリにも、同じ抽出条件を設定しないと、そのような結果になりますね。
T_受講受付 の主キー設定を提示してください。
そのうまくいっているSQLを提示してください。
あと、一時テーブルへデータをエクスポートするときの抽出条件はどこでどのように設定してますか。
レポートのプレビューに[印刷][閉じる]ボタンを付加する関数を下記で紹介していますので、
よろしかったらご参考に。
すみません!解決しました
ありがとうございました。
ポップアップする方法参考にさせていただきます。
ちょっと調べてみましたがメニューバーを表示する場合「ファイル」だけは非表示にできないような感じでした。
「ファイル」の中のメニューは好きに弄れるようです。(「閉じる」を非表示にしたりとか)
Access 2016 のリボンをカスタマイズする
「印刷」だけをさせたいなら右クリックのショートカットメニューをカスタマイズするとか、自分の場合はよく、[印刷]と[閉じる]のボタンだけを置いたフォームをポップアップに設定しておいて、レポートを「印刷プレビュー」で開くと同時にフォームを開くようなものを作ります。
だいたいあってます。
hatena様大変有り難うございました。
考え方としては次の通りでよろしいんでしょうか?
Public Function 月初(申請日 As Variant) As Variant
If IsNull(申請日) Then Exit Function
'申請日がNULLなら関数は終わり
月初 = DateSerial(Year([申請日]), Month([申請日]) + 1, 1)
'月初めが出る
Do
Select Case Weekday(月初)
Case vbMonday To vbFriday
If IsNull(DLookup("祝日名", "T_祝日", "日付=#" & 許可日 & "#")) Then
Exit Do
End If
End Select
月初 = 月初 + 1
Loop
' 月初めが月曜から金曜の間で祝祭日がNULLならD0文が修了。土日はNULLじゃないから終了しない
終了するまで月初に1日プラスする。
End Function
hatena様
閲覧してくださった皆様
有難う御座います
>レポートでなら、「分類」テキストボックスの「重複データ表示」プロパティを「はい」にしておけばいいでしょう
此方でレポートが無事に完成できました
有難う御座います
こんなに設定事項があるんですね
驚きました
時間を作って弄ってみます
重ねてアドバイス有難う御座いました
レポートでなら、「分類」テキストボックスの「重複データ表示」プロパティを「はい」にしておけばいいでしょう。
hatena 様
いつもありがとうございます。
正常に動作できるようになりました。
難しいですが理解できるように勉強致します。
下記でどうでしょうか。
親子関係でもできますが、集計等が複雑になるのでそこまですることはないと思います。
また、現状の割増等のフィールドを持たせる方法もあまりいい方法とはいえないと思います。
夜間割増以外にも、その他の割増とか割引とか増えてきたりするとその都度テーブル、クエリ、フォーム、レポートの修正が発生します。集計も複雑になります。
単純に「割増」というレコードを追加するのが一番シンプルだと思います。
日付 項目名 料金
○月○日 作業A 10000
○月○日 夜間割増 5000
DLookup の第3引数は抽出条件式を文字列として設定します。
現状は、
"文字列" AND "文字列"
となってますので、文字列に対する論理演算になり常にFalseになります。AND は""の中にいれてください。
次に、[テキスト2]が""内に入ってますので、これは単なる"[テキスト2]"という文字列になります。[テキスト2]コントロールを参照するには""の外に出す必要があります。
これで例えばテキスト2が「4月」、テキスト0が「5~6年」なら、第3引数は下記のような条件式として正しい文字列になります。
[月]='4月' And [学年]='5~6年'