質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

1回答

2034閲覧

SQL 重なっている時間を按分して作業時間を求める

yamakawa03

総合スコア20

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2021/05/17 22:49

編集2021/05/18 03:20

SQLで質問です。

  • 作業時間を求めたい。
  • 同じ工程を複数の作業者が作業した時間は按分。

MySQL: 5.7.31

Reportsテーブル
|id|process_id|employee_id|started_on|finished_on|
|--:|--:|--:|
|1|1|1|2021-05-18 9:00:00|2021-05-18 17:00:00|
|2|1|2|2021-05-18 10:00:00|2021-05-18 11:00:00|

単純に作業時間(working_time)を求めると
9:00~18:00 = 8時間 = 8時間×60分×60秒 = 28800秒
10:00~11:00 = 1時間 = 1時間×60分×60秒 = 3600秒
|id|process_id|employee_id|started_on|finished_on|working_time|
|--:|--:|--:|
|1|1|1|2021-05-18 9:00:00|2021-05-18 17:00:00|28800秒|
|2|1|2|2021-05-18 10:00:00|2021-05-18 11:00:00|3600秒|

<<求めたい作業時間>>
10:00~11:00は重なっているので、重なっている件数で割る
9:00~18:00 = 8時間 = 7時間×60分×60秒 + 1時間×60分×60秒 / 2 = 27000秒
10:00~11:00 = 1時間 = 1時間×60分×60秒 / 2 = 1800秒
|id|process_id|employee_id|started_on|finished_on|working_time|
|--:|--:|--:|
|1|1|1|2021-05-18 9:00:00|2021-05-18 17:00:00|27000秒|
|2|1|2|2021-05-18 10:00:00|2021-05-18 11:00:00|1800秒|

10:00~11:00は重なっているので、重なっている件数で割る
1:9:00~18:00 = 8時間 = 7時間×60分×60秒 + 1時間×60分×60秒 / 3 = 26400秒
2:10:00~11:00 = 1時間 = 1時間×60分×60秒 / 3 = 1200秒
3:10:00~11:00 = 1時間 = 1時間×60分×60秒 / 3 = 1200秒
|id|process_id|employee_id|started_on|finished_on|working_time|
|--:|--:|--:|
|1|1|1|2021-05-18 9:00:00|2021-05-18 17:00:00|26400秒|
|2|1|2|2021-05-18 10:00:00|2021-05-18 11:00:00|1200秒|
|3|1|3|2021-05-18 10:00:00|2021-05-18 11:00:00|1200秒|

10:00~11:00と13:00~13:30は重なっているので、重なっている件数で割る
1:9:00~18:00 = 8時間 = 6.5時間×60分×60秒 + 1時間×60分×60秒 / 2 + 0.5時間×60分×60秒 / 2 = 26100秒
2:10:00~11:00 = 1時間 = 1時間×60分×60秒 / 2 = 1800秒
3:13:00~13:30 = 1時間 = 0.5時間×60分×60秒 / 2 = 900秒
|id|process_id|employee_id|started_on|finished_on|working_time|
|--:|--:|--:|
|1|1|1|2021-05-18 9:00:00|2021-05-18 17:00:00|26100秒|
|2|1|2|2021-05-18 10:00:00|2021-05-18 11:00:00|1800秒|
|3|1|3|2021-05-18 13:00:00|2021-05-18 13:30:00|900秒|

※日付を跨ぐことはないのが前提

これをSQLにて求めることはできますでしょうか?

少し考えたのは以下のSQL

SQL

1select 2 sum(seconds) 3from 4( 5 select 60 / count(*) as seconds from reports where process_id = 1 and started_on < '2021-05-18 9:00:00' and finished_on > '2021-05-18 9:00:00' 6 union all 7 select 60 / count(*) as seconds from reports where process_id = 1 and started_on < '2021-05-18 9:01:00' and finished_on > '2021-05-18 9:01:00' 8 union all 9 select 60 / count(*) as seconds from reports where process_id = 1 and started_on < '2021-05-18 9:02:00' and finished_on > '2021-05-18 9:02:00' 10 ・・・ 11 union all 12 select 60 / count(*) as seconds from reports where process_id = 1 and started_on < '2021-05-18 18:00:00' and finished_on > '2021-05-18 18:00:00' 13) a

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sousuke

2021/05/17 23:56

開始、終了時間に30分などは入りますか?
m.ts10806

2021/05/18 00:09

アプリケーション側では使わないのですか? アプリケーション側で計算したほうが楽にできそうですが
yamakawa03

2021/05/18 00:19

>開始、終了時間に30分などは入りますか? はい、入ります。1分単位で変動します。 >アプリケーション側では使わないのですか? アプリケーション側で処理することも可能です。 SQLで取得できる方法があるかなと思い投稿させて頂きました。
sazi

2021/05/18 00:19

MySQLのバージョンは何でしょう?
yamakawa03

2021/05/18 00:22

>MySQLのバージョンは何でしょう? MySQL: 5.7.31 です。 追記しておきます。
sazi

2021/05/18 00:45 編集

@m.ts10806 さん > アプリケーション側で計算したほうが楽にできそう SQLだとemployee_idの総当たりは思いつくところですけど、アプリケーション側で楽できそうなのはどんなロジックでしょうか?
sazi

2021/05/18 02:57 編集

@yamakawa03さん ちょっと考えてみましたが、複数人や日付を跨る事などを考慮すると、決め事が必要だと思われますので、もう少し掘り下げたロジックを追記された方が良いかと思います。
yamakawa03

2021/05/18 03:07

@sazi ありがとうございます。 少し条件が足りなかったので、追記させて頂きます。
neko_the_shadow

2021/05/18 03:51

一度に処理したいprocess_idは1種類だけでしょうか? (上の例であればprocess_id=1のみ、計算がされればよくて、process_id=2やprocess_id=3を同時に計算する必要はないということであっていますか?)
sazi

2021/05/18 03:59

時間の刻みの最小単位は何ですか? スケール(目盛)を作ってその単位でカウントするのが一番シンプルになりそうなんですけど、スケールの単位が細かすぎるとレスポンス的にちょっとどうかなと思うので。
m.ts10806

2021/05/18 04:05

saziさん 私のSQLスキルもあると思いますが、「按分する」というところがあるのでアプリケーションロジックでやってしまいたいなと感じた次第です。
yamakawa03

2021/05/18 05:06

>一度に処理したいprocess_idは1種類だけでしょうか? (上の例であればprocess_id=1のみ、計算がされればよくて、process_id=2やprocess_id=3を同時に計算する必要はないということであっていますか?) できれば、複数process取れるのが理想です。 >時間の刻みの最小単位は何ですか? 1秒単位で欲しいですが、1分単位でも可。
guest

回答1

0

ベストアンサー

個人ごとに作業時間が違うので、基準となる目盛を作り、その目盛単位で重複を数えるのがシンプルです。
例えば、以下の様なテーブルを用意します。
※値は計算範囲に合わせる。
時間帯が9:00~17:00などと決まっているなら、日付は無しにして固定でも良いでしょう。
time_scale

from_timeto_time
2021-05-18 09:00:002021-05-18 10:00:00
2021-05-18 10:00:002021-05-18 11:00:00
2021-05-18 11:00:002021-05-18 12:00:00
2021-05-18 12:00:002021-05-18 13:00:00
2021-05-18 13:00:002021-05-18 14:00:00
2021-05-18 14:00:002021-05-18 15:00:00
2021-05-18 15:00:002021-05-18 16:00:00
2021-05-18 16:00:002021-05-18 17:00:00
2021-05-18 17:00:002021-05-18 18:00:00
2021-05-18 18:00:002021-05-18 19:00:00
2021-05-18 19:00:002021-05-18 20:00:00

上記に対してそれぞれの単位での案分値を求めます。
※目盛は60分なので、60分に対して重なりで除算します。

SQL

1select process_id, from_time, to_time 2 , ( 3 60 / sum(case when from_time <= finished_on and to_time > started_on then 1 end) 4 ) as Profit_time 5from Reports, time_scale 6group by process_id, from_time, to_time

これに対し、各々の作業時間を上記と突合したものを合計します。

追記

時間帯が日付を跨らず固定にできる場合は、以下のようになります。

from_timeto_time
09:00:0010:00:00
10:00:0011:00:00
11:00:0012:00:00
12:00:0013:00:00
13:00:0014:00:00
14:00:0015:00:00
15:00:0016:00:00
16:00:0017:00:00
17:00:0018:00:00
```SQL
select process_id, from_time, to_time
, (60 / sum( case when from_time <= time(finished_on) and to_time > time(started_on) then 1 end ) ) as Profit_time

from Reports, time_scale
group by process_id, from_time, to_time

投稿2021/05/18 04:58

編集2021/05/18 05:59
sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamakawa03

2021/05/18 07:35

ありがとうございます! あらかじめテーブルを作るのは目から鱗でした。  ※レスポンス的にも良さげです。 こちらで行けそうです。
sousuke

2021/05/18 07:41

個人的に思いつく現実的なラインはこの手法なんだけど ここまでして求めた秒数だが何に使うにしても微妙な感じがしてしまうなあ あくまで個人的な感想だけど。1秒の価値を何人で作業しても変わらない前提ならほかに やりようがある気がしないでもない。
sazi

2021/05/18 07:53 編集

@sousukeさん 根本的な事を言うと、複数人で作業すると時間の価値が下がる(生産性が落ちる)というのは在りえないと思いますけどね。 共同作業でフォローする人の生産性が落ちる事はあるでしょうけど、全体でみると上がるから共同作業するのでしょうし。
sousuke

2021/05/18 08:26

@sazi氏 「複数人で作業すると時間の価値が下がる(生産性が落ちる)」 これは私もそう思います、オブラートに包んで発言していました笑 考えられることとしてはこの秒数を何かの分母に使っていて、間接的に価値を上げているのかな? と想像はしていますが…エスパーになるのでわかりませんね~
sazi

2021/05/18 12:53

これって、本来は人を軸にプロセスで案分するって事じゃないかなぁ。
yamakawa03

2021/05/18 13:12

@sazi ご指摘の通りです。 こちらの仕様の把握が間違っておりました。 プロセスと人を変えて対応いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問