SELECT min( ymd ) As d_from
, max( ymd ) As d_to
FROM
(
SELECT x.ymd
, count(1) As n
FROM q_ymdlist x
, q_ymdlist y
WHERE x.ymd >= y.ymd
GROUP BY x.ymd
) q
GROUP BY ymd - n ;
q_fromto
d_from
d_to
2021/08/11
2021/08/12
2021/08/23
2021/08/23
SELECT x.d_from
, x.d_to
, max( iif( y.終了日 Is Null, y.開始日 ) ) As high
, max( y.開始日 ) As low
FROM q_fromto x
LEFT JOIN 単価マスタ y
ON (
(
x.d_from > y.開始日
AND
y.開始日 >= dateserial( year( date() ), month( date() ), 1 )
)
)
GROUP BY x.d_from
, x.d_to ;
q_highlow
d_from
d_to
high
low
2021/08/11
2021/08/12
2021/08/01
2021/08/05
2021/08/23
2021/08/23
2021/08/13
2021/08/20
SELECT x.d_from
, x.d_to
, y.開始日 As 基準開始日
, 1 As 補填行
, y.単価
FROM q_highlow x
, 単価マスタ y
WHERE cdate( nz( x.high, x.low ) ) = y.開始日 ;
q_union
d_from
d_to
基準開始日
補填行
単価
2021/08/11
2021/08/12
2021/08/01
1
150
2021/08/23
2021/08/23
2021/08/13
1
100
SELECT 開始日 As 指定開始日
, 終了日 As 指定終了日
, 開始日 As 基準開始日
, 0 As 補填行
, 単価
FROM q_base
UNION ALL
SELECT d_from
, d_to
, 基準開始日
, 補填行
, 単価
FROM q_union
ORDER BY 1 ;
Private Sub 日付_AfterUpdate()
Dim res
res = DLookup("単価", "単価マスタ", "#" & Me.日付 & "# Between 開始日 AND 終了日")
If IsNull(res) Then
res = DMax("開始日", "単価マスタ", "#" & Me.日付 & "# >=開始日 AND 終了日 Is Null")
If Not IsNull(res) Then
Me.単価 = DLookup("単価", "単価マスタ", "#" & res & "#=開始日")
End If
Else
Me.単価 = res
End If
End Sub
hirotonさんの提示したテーブルなら、下記の1行のコードで済みます。
Me.単価 = DLookup("単価", "単価マスタ", "#" & Me.日付 & "# Between 開始日 AND 終了日")
Private Sub 日付_BeforeUpdate(Cancel As Integer)
If Not IsNull(DLookup("日付", "テーブル名", "日付=#" & Me.日付 & "#")) Then
MsgBox "既に入力された日付です。異なる日付を入力してください"
Cancel = True
End If
End Sub
Private Sub 日付_BeforeUpdate(Cancel As Integer)
If Not IsNull(DLookup("日付", "テーブル名", "日付=#" & Me.日付 & "#")) Then
If MsgBox("既に入力された日付です。登録してもいいですか?", vbOKCancel) = vbCancel Then
Cancel = True
End If
End If
End Sub
例えば
のようなデータの時、
指定日=2021/08/15
の場合すると
と、2レコードHITします
これは、つまり、このようなレコードは存在しないということでしょうか?だとすると、終了日に値の存在が許されるレコードは1つだけという歪なテーブル構造なんでしょうか?
質問の解自体はhatenaさんの回答の通りでしょう。ただ、手順や処理時間で見た簡略化は見込めないと思います。この観点から言えば
ないです
しかしながら、データ構造の観点から言えば、「一時的に変わる時」のデータは単純に追加するだけで済むというメリットができ、データ管理面での単純化なら見込めます
さらに言えば、既に指摘している通り、なぜ最終的なデータ構造でテーブルを作らないのか?という話になります。データ構造が単純で、データの取得もシンプルです
単純=「簡単」とは限らないですが、テーブル構造からはわからない独自ルールを運用するよりはよほど「簡単」でしょう。
本当の主題はこれですよね?
ならば、職人芸のようなテーブル構造・データ取得を考えるよりも単純に「期間限定明け後のデータ入力(ここでは8/11~8/19)を」自動化したいと考えるべきでしょう
( 続き )
q_fromto
q_highlow
q_union
q_result
( 続き )
# 最初は SQLの一筆書きを投稿しようとしたところ
# 160行の記述が長すぎて投稿不可であったことと
# サブクエリのネストが深くて、記述が複雑怪奇になったため、
# 構造別にクエリを複数( 計7つ )作るという回答に切り替えました。
まぁ...個々の記述が短いと 最終結果が出るまでの工程も分かりやすいでしょう。
( クエリを作る順番も、掲載した順と同じになります )
q_base
q_ymd
q_ymdlist
私個人は、hirotonさんやhatenaさんと同じく
ソリューションとしては 圧倒的に
{ テーブルデータの保有形式を変更 } >>> { トリッキーな SQL または VBA }
という見解です。
ただ Access の一般機能で「 実現可能 」な ご要望であることも事実ですから
実用性とパフォーマンスは度外視で、SQL( クエリ )のサンプル を載せておきます。
( ※ 今回の投稿はテーブル定義とデータ例のみ )
なお、( 何らかの )日付範囲の抽出条件を満たした後のデータが
「 例 」の3行であるとするなら
「 指定日付 」に該当するような パラメータなりリテラル値は
開始日フィールドに指定された可能性が高いと推測し、
私の回答( SQL )では、現状のテーブルデータに影響を与えない抽出条件として
を指定しています。
■テーブル: 単価マスタ
■テーブル: T_num
( T_num テーブル の num には 0 ~ 9 までの数値を入力 )
下記が参考になると思います。
レポートをグループ毎に分割してPDFファイルとして保存したい - hatena chips
有り難うございます!やりたいことが実現できました。大変助かりました。
追加の質問があります。
1つのボタンで、一覧に表示されている請求書を1件つづ、自動的にPDF保存を繰り返し行わせるには、どのように記述したら
よいでしょうか。
可能であれば、ご教示頂きたく、よろしくお願いいたします。
hirotonさんの提示したテーブルのような形にしない限りは、簡単にはならないと思います。
どのようなUIなのか不明なので、
フォーム上に「日付」と「単価」というテキストボックスがあると仮定すると、
下記のようなコードで期待する結果にはなります。
hirotonさんの提示したテーブルなら、下記の1行のコードで済みます。
2レコード以上は範囲入力側の制御の時点で入れられない形にしています
>(8/5~8/10 & 8/6~8/11のような複数で日付が被る形はありません)
あくまで終了日付が入るのは期間限定の臨時の時だけで基本的には開始日で単価を制御するようになっており、
単価情報を入力する側が期間限定明け後のデータ入力(ここでは8/11~8/19)を意識しなくてもいい形にしたいというものです
これ、結果は一意じゃないですよね。2レコード以上HITしたらどうしてるんですか?
このデータ形式でテーブルを作らないのは何故なんでしょう?
重複を許さないだけならすでに挙げた方法でいいですが、既定のメッセージじゃ使いにくいのはありますね。2つ目の方法でメッセージを出してキャンセルする(=条件分岐を入れない)ようにすればいいです
返信がわかりづらかったので、
再投稿です。
(レスの引用の仕方が
いまいちよく把握できてません)
りんごさん、hirotonさん
お二人様
御指南ありがとうございます。
どちらもかなり難しそうなので、
しばらくお時間をください。
ちょっと研究してみようと思います。
>hirotonさん
>これはOKなら重複を許すということですか?
これは、自分で書きながら、
改めて考えると重複を一切許さない方がいいかな?
と思いました。重複のお知らせと
入力キャンセルのみのメッセージボックスが
開いた方がいいかもしれないと思いました。
こうした場合は、どうしたらよいでしょう?
りんごさん、hirotonさん
お二人様
御指南ありがとうございます。
どちらもかなり難しそうなので、
しばらくお時間をください。
ちょっと研究してみようと思います。
>hirotonさん
これはOKなら重複を許すということですか?
これは、自分で書きながら、
改めて考えると重複を一切許さない方がいいかな?
と思いました。重複のお知らせと
入力キャンセルのみのメッセージボックスが
開いた方がいいかもしれないと思いました。
こうした場合は、どうしたらよいでしょう?
ごめんなさい、こちらにミスがありました。『リンク親フィールド:日付ID、リンク子フィールド:日付ID』のつもりが、『リンク親フィールド:日付、リンク子フィールド:日付』となっていました。サブフォームで示した件は間違いです。
下記のような感じでどうでしょうか。
hiroton様
確かにそうですね。。。
アドバイスの通りに処理を入れ替えてみました。
結果は30秒ほどで処理が完了し、Excel側も希望通りの値に変更になっておりました。
本当にありがとうございました。
閉じた後に設定の変更って効く(意味がある)んですかね?
あと、設定を有効にする前に保存しているから設定が保存されないのでは?
処理の順番を入れ替えたらどうでしょう?
ついでに、主体はExcel VBAの話なので、解決が難しいようならExcel VBAに強い質問サイトを探すといいと思います
インデックスを使用してテーブル フィールドの値の重複を防ぐ
これはOKなら重複を許すということですか?
上記方法はデータベース的に重複を許さない形なので、これをやりたい場合は自前で制御を組む必要があります。更新前処理イベントで入力しようとした値がすでに登録されているかどうかチェックすればいいですね
まずは、状況確認ですが、もしかしてこんな感じですか?
あと、どのテキストボックスがイメージに近いでしょうか?
親テーブル:日付ID,日付
子テーブル: 主キー,日付ID,その他
メインフォーム連結クエリ:日付ID,日付
サブフォーム連結クエリ:主キー,日付ID,日付,その他
↪フォームヘッダー
日付テキストボックス(非連結):⬜⬜⬜
↪詳細
日付ID:(新規)
日付 :⬜⬜⬜
↪フォームフッダー
📋サブフォーム
↪サブフォームヘッダー
日付テキストボックス(非連結):⬜⬜⬜
↪サブフォーム詳細
↓
↓
↓
↓
2021/08/18↓ 親テーブル
いろいろな見解があると思いますが、
私は非連結フォームはほぼ使いません。
よってDAOからレコード操作もほとんど使いません。
どこにそのような情報があったか知りませんが、
クエリを使わないなら、Accessで開発する意味はないと思います。
皆様ご回答ありがとうございます。
”上”と相談して、64bit版のofficeのPCで再確認したところ、
32bitのofficeで作成したaccdeは開けず、accdbは開けました。
64bitのofficeでaccdbからaccdeを作成すると、accdeは開けました。
ということで、大体解決しそうです。(あとは先方のpcで開けるか確認します)
ありがとうございました。
不具合解決にエラーメッセージは大事です。追記されているようなのでそれっぽい内容で検索してみました
ACCDEファイルが32Bit版と64Bit版で共有できない : Access(FeedSoftさん)
検索の仕方を変えればmicrosoftのドキュメントにも同様の内容を見つけられますね
そういうことでしょう
回答ありがとうございました。
hatena様の見解を参考にさせていただきます。
経験上、8人ぐらいなら、連結でもそんなに重くならないと思います。
新規データの入力フォームなら、「データ入力用」プロパティを「はい」にしておけば全レコードを読みに行くこともないので。
たまに、そのような話も見かけますが、実際、非連結でのコードはそんなに簡単ではないし、そんなにメリットはないと思います。
共有時の非連結フォームに関する私の見解は下記の質問にも回答してますので、参考にしてください。
デフォルトの楽観的排他制御 Microsoft Access 掲示板 - zawazawa
回答ありがとうございます。
非連結で入力フォームを作成したのは、作動が重くならないとNETで見つけたからです。
連結でも、非連結でも、作動は、関係ないのでしょうか?
環境としては、ネットワークドライブで、ACCESSを8人で共有して利用しています。
この入力フォームが連結フォームで連結したテーブルを更新するのが目的なら、そもそもADOもDAOも必要ありません。
というかVBAコード自体必要ありません。
VBAでテーブル更新しているということは、非連結フォームで設計しているのでしょうか。
だとしたら、非連結にしている目的はなんでしょう。
検索しても見つからないのは、Accessにおいてそのようなことする必然性がほぼないからです。
ありがとうございます。
該当ファイルはカレンダーコントロールは使っていないようですが、類似した何かを使っているのでしょうかね。
それが一番ですか。上と相談してみます。ありがとうございました。
フォームかレポートにカレンダーコントロールとかのActiveXコントロールを使っていませんか。
最終的には相手先と同じバージョンにして開発するのが確実な方法だと思います。
hatena様
ご回答ありがとうございます。参照のページ、拝読いたしました。内容は理解できたと思います。
今回問題になっているファイルに、Declareを使っていないと思うのです。
Accessクラスオブジェクトと、標準モジュールのところで、検索しましたがヒットしません。
また、APIのような機能を使ってプログラムをした覚えもありません。(そもそも理解していません)
accessの理解が低くて大変申し訳ありませんが、Declare文とはもっと違うところに書かれているのでしょうか。
ご回答ありがとうございます。
抽出条件に1と入力というのは、主キーで抽出するということでしょうか。
主キーで「1」や「2」と抽出すると、ちゃんとそれに該当するレコードが表示されます。
品目で抽出するとうまく抽出されません…
通常は32bitOfficeで作成したデータベースファイルを64bitOfficeで使用可能です。
ただし、ActiveXコントロールを使っていたりすると使用できません。
ActiveXは使わないようにする必要があります。
また、VBAでWindowsAPIを使っている場合は、API宣言を質問のリンク先の方法で修正する必要があります。
API宣言の修正方法は下記の方がより詳しいです。
WindowsAPI をOffice64bit版または32bit版のVBAで使うには | hatena chips
わざわざメインーサブにフォームを分けなければいいんじゃない?
フォームの挿入前処理イベントで
Me.日付ID = 1
とでもすれば登録だけならできるよ返信の機能がよく分からず、
見えづらい投稿となってすみません。
以後もっとわかりやすく投稿したいと思います。
ご返答をありがとうございます。
>メインフォームとサブフォームのレコードソースのそれぞれのテーブルの関係は、一対多の関係でしょうか。
無理でしたか。残念です。
>現状のメインフォームとサブフォームのレコードソースのそれぞれのテーブルのフィールド構成はどうなってますか。
詳しく記載していただき、誠にありがとうございます。
例えば、サブフォームにしていたものを、
ボタンでフォームを開くといった形にしようかな?と思います。
またご質問することがあるかと存じますが、
その時もよろしくお願い致します。
フォーム(メインフォーム)上にサブフォームコントロールを配置して、
それの「リンク親フィールド」「リンク子フィールド」プロパティを 日付ID に設定しているという状況でしょうか。
フォーム(メインフォーム)の日付ID はオートナンバー型のフィールドでしょうか。
フォーム(メインフォーム)は未入力、つまり新規レコードの状態で、
サブフォームの方でデータを入力したいということでしょうか。
メインフォームとサブフォームのレコードソースのそれぞれのテーブルの関係は、一対多の関係でしょうか。
だとしたら、原理的に無理です。一側のレコードがないと多側のレコードは入力できません。リレーショナルデータベースの制限です。
現状のメインフォームとサブフォームのレコードソースのそれぞれのテーブルのフィールド構成はどうなってますか。
テーブル設計、あるいはメイン/サブフォーム形式が適切でない可能性があります。
ググッただけですが、連結値と表示値を理解するとあります。抽出条件に1と入力するとどうなりますか?
解決いたしました。
ありがとうございました。
引数で対象コントロールを渡せはいいでしょう。
標準モジュール
フォームモジュール
「宛名ラベルを押した瞬間」の宛名ラベルとは具体的になんのことでしょうか。