Microsoft Access 掲示板

「クエリが複雑すぎます」を回避したい

14 コメント
views
4 フォロー

お世話になります。初歩的な質問で申し訳ありません。
「クエリが複雑すぎます」を回避するために分割クエリを作成して一つにまとめようとしたのですが、
レコード数が増えてしまい困っています。

Access2016を使用しています。
勤務表からデータを抽出しようとしています。
勤務開始から終了まで(残業、中抜け含む)を取得しようとしています。

すべてをまとめて一つのクエリで出そうとしたところ、「クエリが複雑すぎます」と出てしまいました。
そこで分割してクエリを作成し、それを一つにまとめようとしたところ、
今度は本来のレコード数よりも多くなりました。
固有の値を「はい」にしてもレコード数は一致しませんでした。
個別のレコードと認識できるようにキーワード用のフィールドも作成してみましたがだめでした。
何か方法はないでしょうか。

・同じ人で複数のレコードがある場合があります
(日中数時間勤務、夕方にも勤務、夜中にも勤務の場合2レコードに分れる)
・勤務中中抜けしている場合もあります。中抜けしている時間(開始と終了)も取得したいです。
・休日出勤もあります。休日出勤の勤務開始時間は平日の勤務開始と異なるフィールドに入っています
・フレックス勤務あります。フレックス勤務の開始時間も別のフィールドに入っています。
・残業開始時間、終了時間はそれぞれ3つずつのフィールドに分れています

ひとまず休日出勤用、平日勤務用、フレックス対応用の3つに分けてクエリを作成してあります。
最終的には一つのテーブルとしてまとめたいです。

抽象的な質問で申し訳ありません。よろしくお願いします。

ひんやり
作成: 2021/09/16 (木) 20:44:27
通報 ...
1
りんご 2021/09/16 (木) 21:57:58 c564b@0e907

勤務表からデータを抽出しようとしています。

 勤務表は、こんな感じですか?
 1つのレコードに、名前、日付、休日開始時間、休日終了時間、休日残業開始時間、休日残業終了時間、平日開始時間、平日終了時間、平日残業開始時間、平日残業終了時間、フレックス開始時間、フレックス終了時間、フレックス残業開始時間、フレックス残業終了時間が記録される。

・勤務中中抜けしている場合もあります。中抜けしている時間(開始と終了)も取得したいです。

 どのように記録していますか?例えば、平日勤務8:20〜17:20、中抜け14:00〜15:00の場合、開始時間8:20終了時間14:00と開始時間15:00終了時間17:20の2レコード。

最終的には一つのテーブルとしてまとめたいです。

 名前、日付、勤務開始時間、勤務終了時間、中抜け開始時間、中抜け終了時間、残業開始時間、残業終了時間みたいな感じにしたいのでしょうか?

 タイムカードの有無、中抜け記録と残業記録のタイミング(後日、報告?)など追加情報があれば、他の人のアドバイスが増えるかも。

2
ひんやり 2021/09/16 (木) 23:43:18 8be4a@c8e67

ありがとうございます。
レコードはこんな感じです。
名前、日付、平日開始時間、平日終了時間、残業1開始、残業1終了、残業2開始、残業2終了、残業3開始、残業3終了、
時間休開始、時間休終了、休日1開始時間、休日1終了時間、休日2開始時間、休日2終了時間、
フレックス開始、フレックス終了

平日出勤した時点で、自動的に平日開始と平日終了時間が入ります。
午前休や午後休を取得した場合でも、平日開始と平日終了は変わりません。固定です。
時間給(中抜け)や午前休などを取得したかどうかは、時間休開始と時間休終了で判断します。
残業1が始業前残業、残業2が後残業です。残業3は残業1の前だったり残業2の後だったりと不定です。
フレックスは残業なしという扱いです。

どのように記録していますか?例えば、平日勤務8:20〜17:20、中抜け14:00〜15:00の場合、開始時間8:20終了時間14:00と開始時間15:00終了時間17:20の2レコード。

基本的には1レコードです。
中抜けは、平日と休日で変わります。
・平日の場合:開始時間8:20(固定)、終了時間17:20(固定)、時間休開始14:00、時間休終了15:00
・休出の場合:休日1開始時間8:20、休日1終了時間14:00、休日2開始時間15:00、休日2終了時間17:20

2レコードに分れるのは休出限定だと思います。
頻度はそれほど出ないけど、よく出る(?)らしいです。
勤務時間 8:00~10:00、10:30~12:00、19:00~20:00
(1レコード目)休日1開始8:00、休日1終了10:00、休日2開始10:30、休日2終了1:00、
(2レコード目)休日1開始19:00、休日2終了20:00

名前、日付、勤務開始時間、勤務終了時間、中抜け開始時間、中抜け終了時間、残業開始時間、残業終了時間みたいな感じにしたいのでしょうか?

抽出したいのは、名前、日付、勤務開始、勤務終了、中抜け開始、中抜け終了です。
勤務時間は残業も含めた時間を出したいです。
開始時間は始業前残業開始時間から、終了時間は後残業終了までです。

タイムカードの有無、中抜け記録と残業記録のタイミング(後日、報告?)など追加情報があれば、他の人のアドバイスが増えるかも。

ありがとうございます。
勤務表データは、一月分ずつまとまってきます。
そのため、必要なデータはすべて入力済みの状態で手元に来ます。
オンライン勤務表なのであまり詳しくはわからないのですが、
PCのONとOFF時間を取得しているようなので、残業1~3は、おそらく内部で自動的に振り分けていると思います。

取得したい項目は少ないのに、関連する項目が多くて困っています。
よろしくお願いします。

3
ひんやり 2021/09/16 (木) 23:48:28 8be4a@c8e67

すみません、入力間違えました。正しくは以下のとおりです。

2レコードになるパターンは、
勤務時間 8:00~10:00、10:30~12:00、19:00~20:00
(1レコード目)休日1開始8:00、休日1終了10:00、休日2開始10:30、休日2終了1:00、
(2レコード目)休日1開始19:00、休日1終了20:00

5
hiroton 2021/09/17 (金) 08:43:51 36d08@f966d >> 3

抽出したいのは、名前、日付、勤務開始、勤務終了、中抜け開始、中抜け終了です。

2レコードになるパターンは、
勤務時間 8:00~10:00、10:30~12:00、19:00~20:00
(1レコード目)休日1開始8:00、休日1終了10:00、休日2開始10:30、休日2終了1:00、
(2レコード目)休日1開始19:00、休日1終了20:00

この場合最終的にはどういうデータにしたいんでしょう?
1.中抜けなしの3レコードにする
2.それぞれそのまま扱う(1レコード目は中抜けあり、2レコード目は中抜けなし)
3.1レコードにまとめる(中抜けの表現はどのように?)

7
ひんやり 2021/09/17 (金) 09:49:38 8be4a@c8e67 >> 5

2で行こうと思っています。
作成し始めたばかりの時に、私のスキルでは1つにまとめるのは難しいとお話しし、了承をいただいています

8
hiroton 2021/09/17 (金) 09:55:51 36d08@f966d >> 3

では、具体的に処理した場合どんなデータになりますか?

1レコード目

休日1開始休日1終了休日2開始休日2終了
8:0010:0010:301:00

勤務開始勤務終了中抜け開始中抜け終了
????????????????

2レコード目

休日1開始休日1終了休日2開始休日2終了
19:0019:00

勤務開始勤務終了中抜け開始中抜け終了
????????????????
4
りんご 2021/09/17 (金) 07:28:32 c564b@0e907

 ちょっと、複雑なので、フレックスと残業3は抜きに、方向性を考えてみました。

(1レコード目)休日1開始8:00、休日1終了10:00、休日2開始10:30、休日2終了12:00、

休日1開始休日1終了休日2開始休日2終了残業1開始残業1終了残業2開始残業2終了
8:0010:0010:3012:007:007:3013:0014:00
Is Not NullIs Not NullIs Not NullIs Not Null

︎休日1と残業1を仮テーブルに追加クエリその1(休日2と残業2は追加先を指定しない)を作る。
︎休日2と残業2を仮テーブルに追加クエリその2(休日1と残業1は追加先を指定しない)を作る。

(2レコード目)休日1開始19:00、休日1終了20:00

休日1開始休日1終了休日2開始休日2終了残業1開始残業1終了残業2開始残業2終了
19:0020:0018:3021:30
Is Not NullIs Not NullIs NullIs Null

休日1と残業1と残業2を仮テーブルに追加クエリその3を作る。

平日の場合:開始時間8:20(固定)、終了時間17:20(固定)、時間休開始14:00、時間休終了15:00

開始時間終了時間時間休開始時間休終了残業1開始残業1終了残業2開始残業2終了休日1開始休日1終了
8:2017:2014:0015:007:208:2017:2018:20
Is NullIs Null

開始、終了、時間休、残業を仮テーブルに追加クエリその4を作る。

仮テーブル
勤務開始勤務終了残業1開始残業1終了残業2開始残業2終了時間休開始時間休終了
8:0010:007:007:30
10:3012:0013:0014:00
19:0020:0018:3021:30
8:2017:207:208:2017:2018:2014:0015:00
選択クエリ
勤務開始勤務終了残業1開始残業1終了残業2開始残業2終了時間休開始時間休終了
8:0010:007:007:30
10:3012:0013:0014:00
19:0020:00 18:3021:30
8:2017:207:208:2017:20 18:2014:0015:00

︎残業1を新テーブルに追加クエリその5(残業1がIs Not Null)を作る。
︎残業2を新テーブルに追加クエリその6(残業2がIs Not Null)を作る。
︎残業1開始と勤務開始を新テーブルの勤務開始と勤務終了に追加クエリその7を作る。
(残業1開始がIs Not Null、残業1終了がIs Null)
︎勤務終了と残業2終了を新テーブルの勤務開始と勤務終了に追加クエリその8を作る。
(残業2開始がIs Null、残業2終了がIs Not Null)

︎勤務開始、勤務終了、時間休開始、時間休終了を新テーブルの勤務開始、勤務終了、中抜け開始、中抜け終了に追加クエリその9を作る。

新テーブル
勤務開始勤務終了中抜け開始中抜け終了
7:007:30
7:208:20
13:0014:00
17:2018:20
18:3019:00
20:0021:30
8:0010:00
10:3012:00
19:0020:00
8:2017:2014:0015:00

 最後は、クエリで見やすい順番に。

12
ひんやり 2021/09/17 (金) 15:02:43 8be4a@c8e67 >> 4

追加クエリという手がありましたね。うっかりしていました。
選択クエリとテーブル作成クエリで作ることばかりを考えていました
中身の見直しと追加クエリで再挑戦してみます

6
hiroton 2021/09/17 (金) 09:48:11 36d08@f966d

基本的にはクエリを分ける必要はなく、それぞれの入力からそのレコードがどの勤務形態なのかを判定してその時の対応するフィールドの値を取ってこればいいです。
テクニックとして、それぞれの入力が排他的であればそれぞれの時間を合計してあげればほしい時間になります

No通常勤務開始時間休日勤務開始時間フレックス開始時間
18:20
210:00
313:00

↓そのまま開始時間同士を合計する(データなし(Null)は0とする)

NO開始時間
18:20
210:00
313:00

通常勤務の時間は残業時間によって変わるので、この計算の前に残業時間を考慮したデータ上の開始時間を作成します。

通常勤務開始時間: IIf([残業3開始]<[平日開始時間],[残業3開始],Nz([残業1開始],[平日開始時間]))

これらを組み合わせればクエリを分けることなくそれぞれの時間を求めることができます。

開始時間: Nz(IIf([残業3開始]<[平日開始時間],[残業3開始],Nz([残業1開始],[平日開始時間])),0)+Nz([休日1開始時間],0)+Nz([フレックス開始],0)

休日については扱いに不明点があります。>> 5に要点をまとめているので確認してください。それに合わせて事前にデータの整形が必要になります
たぶん、休日2のあるレコードだけ抽出してUNIONすることになるんじゃないかと予想しています

あと、残業3が出るというのは残業と残業の間に中抜けがありそうですがどうなんでしょう?具体的なデータでほしい結果を考えてみてください

もう一つ、フレックスって時間休ないんですかね。扱い的には休日みたいに複数レコード発生とかしてそうですけど(データ処理的には問題ない)

9
ひんやり 2021/09/17 (金) 10:36:09 8be4a@c8e67 >> 6

クエリを考えるのに必死になりすぎて、NZの存在を忘れていました・・・。
ちょっと見直します。

あと、残業3が出るというのは残業と残業の間に中抜けがありそうですがどうなんでしょう?具体的なデータでほしい結果を考えてみてください

残業と残業の間で中抜けは発生しないと思われます。
分析してみましたが、残業開始から早朝帯や深夜帯に入ると残業3が入っているように見えます。

もう一つ、フレックスって時間休ないんですかね。扱い的には休日みたいに複数レコード発生とかしてそうですけど(データ処理的には問題ない)

時間休あります。
平日の普通の勤務と同じ、時間休開始、時間休終了で中抜けを判別しています。
フレックス専用で時間休を値が入るところはないです。

10
hiroton 2021/09/17 (金) 11:12:09 36d08@f966d >> 9

NzはNullを判定するだけなんでIIf条件分岐でIsNull判定するのと同じですけどね。式が短く書けるだけです(大事)

残業3は残業代の切り替わりをわかりやすくしてるだけかな?データ上では意味ないですが業務上ではよくある話ですかね

休日2がある場合に中抜け扱いとすると、平日の時間休に申請があるとき、申請上の時間合計とデータ上の中抜けの時間合計が合わないってことになります。
休日のデータには休日フラグを立てて、そのレコードは集計から省くようにすれば問題ないんですが、hiroton的には元データから存在しないような作りのほうが好きですね
休日1と休日2の間には中抜けがあるけど休日2と休日3(2レコード目の休日1)の間には中抜けがないっていうのも混乱のもとですし

ちょっと挙げたようにUNION使えばできないことでもないですが、ほしい結果次第ですかね。今回は使わなくてもよさそうでそのほうが高速そうでもあります。

>> 8にイメージを出していますが、「休日2発生時は中抜け扱いをする」ならフィールドの位置をうまい具合に入れ替えるような条件判断を作ってあげればいいので考えてみてください

11
hiroton 2021/09/17 (金) 14:25:05 36d08@f966d >> 6

項が分かれていたほうが入れ子少なくてわかりやすいかと思ったけど

開始時間: Nz(IIf([残業3開始]<[平日開始時間],[残業3開始],Nz([残業1開始],[平日開始時間])),0)+Nz([休日1開始時間],0)+Nz([フレックス開始],0)
↓
開始時間: Nz(IIf([残業3開始]<[平日開始時間],[残業3開始],Nz([残業1開始],[平日開始時間])),Nz([休日1開始時間],[フレックス開始]))

勤務終了: Nz(IIf([残業3終了]>[平日終了時間],[残業3終了],Nz([残業2終了],[平日終了時間])),Nz(Nz([休日2終了],[休日1終了]),[フレックス終了]))

長くてもこのくらいなら全部Nzの入れ子の形でも問題なさそう

13
ひんやり 2021/09/17 (金) 15:13:24 8be4a@c8e67 >> 11

おお、なるほど。
お二人の回答を見て大分回りくどいことをやっていたことに気づきました。
かなりごてごて書き込んでしまっているので、少し中身を見直してみます。

14
ひんやり 2021/09/17 (金) 19:51:45 8be4a@c8e67

教えていただきありがとうございました。
内部処理を見直してhirotonさんにご教示いただいたNZを使ってみたのですが、それでもやはり単体では厳しかった(クエリが複雑過ぎますがでました)ため、りんごさんにご教示いただいた追加クエリ等を使った結果、想定していたイメージの通りのものができました。

大変助かりました。
本当にありがとうございました。