Microsoft Access 掲示板

一時的な日付範囲指定を含む日付データからの抽出

8 コメント
views
4 フォロー

お世話になっております
日付範囲で単価を取得するテーブルを作っており、
一時的に変わる時だけ終了日を入れて範囲を決めています
(8/5~8/10 & 8/6~8/11のような複数で日付が被る形はありません)

開始日     終了日     単価
2021/08/01   Null      150
2021/08/05   2021/08/10   120
2021/08/20   Null      140

このようなデータで日付を指定した際に
指定日付 2021/08/01 ~ 2021/08/04 基準開始日 2021/08/01  単価150  
指定日付 2021/08/05 ~ 2021/08/10 基準開始日 2021/08/05  単価120
指定日付 2021/08/11 ~ 2021/08/19 基準開始日 2021/08/01  単価150
指定日付 2021/08/20 ~          基準開始日 2021/08/20  単価140
と基準開始日と単価が返ってくるようにしたいのです

現状は最初に
指定日付>=開始日 AND ISNULL(終了日)=FALSE で抽出後
指定日付<=終了日であればその期間の開始日とその時の単価を取得
そうでなければ指定日付>=開始日 AND ISNULL(終了日)=TRUE の中でMAXの開始日とその時の単位を取得 という形を
取っているのですがこれ以上簡単にできる方法はありませんでしょうか?

tetsusi
作成: 2021/08/20 (金) 14:22:13
通報 ...
1
hiroton 2021/08/20 (金) 17:01:16 13d29@f966d

指定日付>=開始日 AND ISNULL(終了日)=FALSE で抽出後

これ、結果は一意じゃないですよね。2レコード以上HITしたらどうしてるんですか?

このようなデータで日付を指定した際に
指定日付 2021/08/01 ~ 2021/08/04 基準開始日 2021/08/01  単価150  
指定日付 2021/08/05 ~ 2021/08/10 基準開始日 2021/08/05  単価120
指定日付 2021/08/11 ~ 2021/08/19 基準開始日 2021/08/01  単価150
指定日付 2021/08/20 ~          基準開始日 2021/08/20  単価140
と基準開始日と単価が返ってくるようにしたいのです

このデータ形式でテーブルを作らないのは何故なんでしょう?

2
tetsusi 2021/08/20 (金) 17:56:57 b557c@0c0d2

2レコード以上は範囲入力側の制御の時点で入れられない形にしています
>(8/5~8/10 & 8/6~8/11のような複数で日付が被る形はありません)

あくまで終了日付が入るのは期間限定の臨時の時だけで基本的には開始日で単価を制御するようになっており、
単価情報を入力する側が期間限定明け後のデータ入力(ここでは8/11~8/19)を意識しなくてもいい形にしたいというものです

7
hiroton 2021/08/23 (月) 09:54:19 f1def@f966d >> 2

例えば

開始日終了日単価
2021/08/01Null150
2021/08/052021/08/10120
2021/08/112021/08/19130
2021/08/20Null140

のようなデータの時、指定日=2021/08/15の場合

指定日付>=開始日 AND ISNULL(終了日)=FALSE で抽出

すると

開始日終了日単価
2021/08/052021/08/10120
2021/08/112021/08/19130

と、2レコードHITします

2レコード以上は範囲入力側の制御の時点で入れられない形にしています

これは、つまり、このようなレコードは存在しないということでしょうか?だとすると、終了日に値の存在が許されるレコードは1つだけという歪なテーブル構造なんでしょうか?

質問の解自体はhatenaさんの回答の通りでしょう。ただ、手順や処理時間で見た簡略化は見込めないと思います。この観点から言えば

これ以上簡単にできる方法は

ないです

しかしながら、データ構造の観点から言えば、「一時的に変わる時」のデータは単純に追加するだけで済むというメリットができ、データ管理面での単純化なら見込めます

さらに言えば、既に指摘している通り、なぜ最終的なデータ構造でテーブルを作らないのか?という話になります。データ構造が単純で、データの取得もシンプルです
単純=「簡単」とは限らないですが、テーブル構造からはわからない独自ルールを運用するよりはよほど「簡単」でしょう。

単価情報を入力する側が期間限定明け後のデータ入力(ここでは8/11~8/19)を意識しなくてもいい形にしたいというものです

本当の主題はこれですよね?
ならば、職人芸のようなテーブル構造・データ取得を考えるよりも単純に「期間限定明け後のデータ入力(ここでは8/11~8/19)を」自動化したいと考えるべきでしょう

3
hatena 2021/08/20 (金) 18:37:41 修正

hirotonさんの提示したテーブルのような形にしない限りは、簡単にはならないと思います。

どのようなUIなのか不明なので、
フォーム上に「日付」と「単価」というテキストボックスがあると仮定すると、
下記のようなコードで期待する結果にはなります。

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 終了日")
4
mayu 2021/08/21 (土) 10:37:19 修正 ef559@a99f1


開始日     終了日     単価
2021/08/01   Null      150
2021/08/05   2021/08/10   120
2021/08/20   Null      140

このようなデータで日付を指定した際に
指定日付 2021/08/01 ~ 2021/08/04 基準開始日 2021/08/01  単価150  
指定日付 2021/08/05 ~ 2021/08/10 基準開始日 2021/08/05  単価120
指定日付 2021/08/11 ~ 2021/08/19 基準開始日 2021/08/01  単価150
指定日付 2021/08/20 ~          基準開始日 2021/08/20  単価140
と基準開始日と単価が返ってくるようにしたいのです

  
私個人は、hirotonさんやhatenaさんと同じく
ソリューションとしては 圧倒的に
{ テーブルデータの保有形式を変更 } >>> { トリッキーな SQL または VBA }
という見解です。

ただ Access の一般機能で「 実現可能 」な ご要望であることも事実ですから
実用性とパフォーマンスは度外視で、SQL( クエリ )のサンプル を載せておきます。
( ※ 今回の投稿はテーブル定義とデータ例のみ )

なお、( 何らかの )日付範囲の抽出条件を満たした後のデータが
」の3行であるとするなら

指定日付 」に該当するような パラメータなりリテラル値は
開始日フィールドに指定された可能性が高いと推測し、
私の回答( SQL )では、現状のテーブルデータに影響を与えない抽出条件として

    開始日 >= dateserial( year( date() ), month( date() ), 1 ) 

を指定しています。
  

■テーブル: 単価マスタ

CREATE TABLE 単価マスタ
(
      rid    counter  not null primary key
    , 開始日 datetime not null
    , 終了日 datetime
    , 単価   money    not null
);
rid開始日終了日単価
12021/08/01150
22021/08/052021/08/10120
32021/08/13100
42021/08/202021/08/22140
52021/08/2415
62021/08/2830

  
  
■テーブル: T_num  

CREATE TABLE T_num ( num int not null primary key );

( T_num テーブル の num には 0 ~ 9 までの数値を入力 )

num
0
1
2
3
4
5
6
7
8
9
5
mayu 2021/08/21 (土) 10:38:13 修正 ef559@a99f1 >> 4

( 続き )

# 最初は SQLの一筆書きを投稿しようとしたところ
# 160行の記述が長すぎて投稿不可であったことと
# サブクエリのネストが深くて、記述が複雑怪奇になったため、
# 構造別にクエリを複数( 計7つ )作るという回答に切り替えました。

まぁ...個々の記述が短いと 最終結果が出るまでの工程も分かりやすいでしょう。
( クエリを作る順番も、掲載した順と同じになります )

  • SQL文
  • クエリ名
  • SQLの結果セット

 

q_base

開始日終了日単価
2021/08/012021/08/04150
2021/08/052021/08/10120
2021/08/202021/08/22140
2021/08/132021/08/19100
2021/08/242021/08/2715
2021/08/282099/12/3130

 

q_ymd

ymd
2021/8/1
2021/8/2
2021/8/3
 ( 省略)
2021/8/25
2021/8/26
2021/8/27

 

q_ymdlist

ymd
2021/8/11
2021/8/12
2021/8/23
6
mayu 2021/08/21 (土) 10:38:56 修正 ef559@a99f1 >> 5

( 続き )
 

q_fromto

d_fromd_to
2021/08/112021/08/12
2021/08/232021/08/23

 

q_highlow

d_fromd_tohighlow
2021/08/112021/08/122021/08/012021/08/05
2021/08/232021/08/232021/08/132021/08/20

 

q_union

d_fromd_to基準開始日補填行単価
2021/08/112021/08/122021/08/011150
2021/08/232021/08/232021/08/131100

 

q_result

指定開始日指定終了日基準開始日補填行単価
2021/08/012021/08/042021/08/010150
2021/08/052021/08/102021/08/050120
2021/08/112021/08/122021/08/011150
2021/08/132021/08/192021/08/130100
2021/08/202021/08/222021/08/200140
2021/08/232021/08/232021/08/131100
2021/08/242021/08/272021/08/24015
2021/08/282099/12/312021/08/28030
8
tetsusi 2021/08/24 (火) 10:24:54 b557c@0c0d2

ありがとうございます
クエリで日付から単価や開始日を呼び出したりする形で使いたかったので
hatenaさんのコードをもとに標準モジュール(日付を入数化)にする形で対応できました