3

プロジェクト: 私はいくつかの部屋と部屋で使用する機器に関するプロジェクトに取り組んでいます。ソフトウェアは、部屋の機器のスケジュールに関するものです。つまり、選択した機材を必要な日時の範囲で別室に予約する予約ソフトです。Phpで動作するMYsSQLデータベースに多くのテーブルがありますが、質問の対象となるテーブルについて言及します。質問に関連付けるテーブルは、機器テーブル (テーブル A)、スケジュール テーブル (テーブル B)、および関連するスケジュールで使用する機器 (テーブル C) です。

表A:装備一覧表

eqid   | eqName    | available| 

1      |  book     |   90     |      

2      |  pen      |   82     | 

3      |  computer |   25     |

表A; eqid は機器の一意の ID を表し、eqName は機器の名前を表し、available は既存の使用可能な機器の合計を表します。

表B:スケジュール表

scheduleid | startDate  | endDate    | startTime | endTime  |  office  |

1          | 2012-08-27 | 2012-08-27 | 08:30:00  | 10:00:00 |  room1   |

2          | 2012-08-27 | 2012-08-27 | 09:30:00  | 11:00:00 |  room3   |

3          | 2012-08-28 | 2012-08-30 | 08:30:00  | 12:00:00 |  room2   |

4          | 2012-08-29 | 2012-08-31 | 11:30:00  | 14:00:00 |  room1   |

5          | 2012-08-28 | 2012-08-28 | 10:30:00  | 14:00:00 |  room3   |

6          | 2012-08-27 | 2012-08-30 | 08:30:00  | 10:00:00 |  room4   |

7          | 2012-08-27 | 2012-08-27 | 10:30:00  | 12:00:00 |  room4   |    

8          | 2012-08-27 | 2012-08-30 | 08:30:00  | 11:00:00 |  room6   |

9          | 2012-08-27 | 2012-08-27 | 10:30:00  | 12:00:00 |  room5   |

表 B; scheduleid はスケジュールの一意の ID を表し、startDate と endDate はスケジュールの日付範囲、startTime と endTime はスケジュールの時間範囲、office はスケジュールが行われる場所を意味します。ここで例を挙げましょう。スケジュール ID 1 は、2012 年 8 月 27 日の月曜日に予約があり、08.30 から 10:00 までであることを意味します。同じ日に開始および終了するため、これは room1 の 1 日のみの予約です。ただし、Scheduleid 3 は、予約が 2012 年 8 月 28 日火曜日に始まり、2012 年 8 月 30 日木曜日の 08:30 ~ 12:00 まで続くことを意味します。 08:30 から 12:00...つまり、部屋 2 には火曜日から木曜日の 08:30 から 12:00 までの予約があります...これが明確であることを願っています。

表C:関連スケジュールで使用する機器

Autoid  | scheduleid |  eqid   | amountInSch|

1       |     1      |   1     |      2     |      

2       |     1      |   2     |      3     |  

3       |     1      |   3     |      1     |  

4       |     2      |   1     |      1     |  

5       |     2      |   2     |      1     |  

6       |     2      |   3     |      2     |  

7       |     3      |   2     |      1     | 

8       |     3      |   3     |      3     |  

9       |     4      |   2     |      1     |  

10      |     4      |   3     |      1     |  

11      |     5      |   1     |      1     |  

12      |     6      |   1     |      1     | 

13      |     6      |   3     |      2     |  

14      |     6      |   2     |      4     |  

15      |     7      |   1     |      5     |  

16      |     7      |   2     |      6     |  

17      |     8      |   2     |      1     | 

18      |     9      |   1     |      8     |  

19      |     9      |   2     |      5     |  

20      |     9      |   3     |      6     |  

表 C: Autoid は自動インクリメントによって生成された一意の自動 ID を表し、scheduleid は表 B から取得され、eqid は表 A から取得され、amountInSch は関連するスケジュールで使用される機器の数 (金額) を表します。ここで例を挙げたいと思います。表 C の Scheduleid 1 には 3 つの行があります。これは、テーブル B で関連付けられたスケジュール ID 1 が、テーブル B で指定された日付と時刻の room1 で 2 本の本 (eqid 1)、3 つのペン (eqid 2)、および 1 台のコンピューター (eqid 3) を使用することを意味します。もう 1 つの例は、表 C の scheduleid 3 が 2 つの行に関連していることです。これは、2012 年 8 月 27 日から 30 日まで、毎日 08:30 から 12:00 まで、room2 で 1 台のペン (eqId 2) と 3 台のコンピューター (eqId 3) が使用されることを意味します。

上記は説明であり、プロジェクトに関するいくつかの情報を提供します。テーブルの行は永続的ではありません。予約すると、テーブルBに新しい行があり、機器を選択すると、テーブルCに新しい行があります...

質問:

eqId、startDate、endDate、startTime、endTime を指定したときに、特定の機器の残量を計算したい...

例:

eqId: 1 (本)

開始日: 2012-08-27

終了日: 2012-08-27

開始時間: 08:30:00

終了時間: 12:00:00

結果は次のようになります: 14 本がスケジュールで使用され、残りの 76 本が利用可能です

理由: scheduleIds と関連する eqId を見ると、私のクエリ (dates と eqId) に関連する 1、2、6、7、9 の scheduleId しか表示されません。表 C の関連するすべての量を合計すると、間違った結果が得られます。つまり、eqId(1-book) と 1、2、6、7、9 の scheduleId の関連量は、それぞれ 2、1、1、5、8 です。したがって、それらを合計すると、17 になりますが、これは間違っています。1 と 9 のスケジュールは開始時刻と終了時刻が交差せず、6 と 7 のスケジュールも交差しないためです。その結果、2人は孤独なままで、別々に数えることができます. 8 は 2 よりも大きいため、1 と 9 を合計した 8 と見なす必要があります。6 と 7 についても同じです。5 は 1 よりも大きいため、5 と見なされます。

それでは皆さん!プログラミングアルゴリズムでこれをどのように合計できるかわかりません。SQL で行う方法はありますか、それとも PHP と Mysql を一緒に使用する必要がありますか? そしてどうやって?

乾杯!

SQLFiddle レコード

4

1 に答える 1

1

次の SQL から始めて、指定された範囲と交差するすべての日付範囲を収集しました。

SELECT MAX(available) - IFNULL(SUM(amountInSch), 0)
FROM Table1
LEFT JOIN Table3 USING (eqid)
LEFT JOIN Table2 USING (scheduleid)
WHERE DATE(startDate) <= '2012-08-27' AND DATE(endDate) >= '2012-08-27'
  AND endTime > '08:30' AND startTime < '12:00'
  AND eqid = 1

フィドル

これは最初の部分だけです。次に、可能なオーバーラップを解決する必要があります。これを SQL で行うのは現実的ではないため、PHP で行うことをお勧めします。

私が選ぶ一般的なアルゴリズムは、残念ながら O(n**2) です。次のようになります。

  • 時間を横軸にしてタイムライン(日ごとに区切られた)を作成する
  • すべての日付/時間範囲を繰り返し、その左端と右端の時間をマークして、可能なすべての順列の時間セグメントを作成します。
  • セグメントを使用して、オーバーラップを垂直方向に合計し、毎日の最大値を取得します。

それが役立つことを願っています。

于 2012-08-31T07:05:12.893 に答える