4

レンタル システムは予約テーブルを使用して、すべての予約と予約を保存します。

booking | item | startdate        | enddate
1       | 42   | 2013-10-25 16:00 | 2013-10-27 12:00
2       | 42   | 2013-10-27 14:00 | 2013-10-28 18:00
3       | 42   | 2013-10-30 09:00 | 2013-11-01 09:00
…

ユーザーがアイテム 42 を 2013 年 10 月 27 日 12:00 から 2013 年 10 月 28 日 12:00 まで、つまり 1 日レンタルしたいとします。システムは、予約番号がないため、指定された時間枠でアイテムを利用できないことを彼に伝えます。2 衝突します。

ここで、選択したアイテムが再び利用可能になる最も早いレンタル日時を提案したいと思います。もちろん、ユーザーの希望日時からユーザーの希望期間(1日)を考慮します。

上記の場合、2013-10-28 18:00 を返す SQL クエリを探しています。これは、アイテム 42 が 1 日間利用可能になる 2013-10-27 12:00 以降の最も早い日付が2013 年 10 月 28 日 18:00 から 2013 年 10 月 29 日 18:00 まで。

したがって、ユーザーの予約を保持するのに十分な大きさで、希望する開始日にできるだけ近い予約間のギャップを見つける必要があります。

つまり、特定のアイテムの最初の予約を見つける必要があり、その後、ユーザーの予約を行うのに十分な空き時間があります。

これは、すべての予約とその後継者を反復処理する必要なく、単純な SQL で可能ですか?

4

6 に答える 6

3

より効率的なものを使用するようにデータベースを再設計できない場合は、これで答えが得られます。明らかにそれをパラメータ化する必要があります。希望の日付、または雇用間隔が既存の予約と重複しない最も早い終了日を見つけるように指示されています。

Select
    min(startdate)
From (
    select
        cast('2013-10-27 12:00' as datetime) startdate
    from
        dual
    union all
    select
        enddate
    from
        booking
    where
        enddate > cast('2013-10-27 12:00' as datetime) and
        item = 42
    ) b1
Where
    not exists (
        select 
             'x'
        from
            booking b2
        where
            item = 42 and
            b1.startdate < b2.enddate and
            b2.startdate < date_add(b1.startdate, interval 24 hour)
    );

Example Fiddle

于 2013-10-22T23:11:40.060 に答える
2
SELECT startfree,secondsfree FROM (
  SELECT
    @lastenddate AS startfree,
    UNIX_TIMESTAMP(startdate)-UNIX_TIMESTAMP(@lastenddate) AS secondsfree,
    @lastenddate:=enddate AS ignoreme
  FROM
    (SELECT startdate,enddate FROM bookings WHERE item=42) AS schedule,
    (SELECT @lastenddate:=NOW()) AS init
  ORDER BY startdate
) AS baseview
WHERE startfree>='2013-10-27 12:00:00'
  AND secondsfree>=86400
ORDER BY startfree
LIMIT 1
;

いくつかの説明: 内側のクエリは変数を使用して反復を SQL に移動し、外側のクエリは必要な行を見つけます。

そうは言っても、DB構造が与えられたようなものであれば、SQLではこれを行いません。内部クエリでいくつかのスマートを使用して適切な期間に反復回数を減らすことができWHEREますが、これはうまく機能しない可能性があります。

編集

警告: 私はチェックしていませんが、リストに以前の予約がない場合、これは機能しないと思います。この場合、最初の予約試行 (元の時間) が機能するため、これは問題にはなりません。

編集

SQLフィドル

于 2013-10-22T22:48:59.967 に答える
1

OK、これは MySQL ではきれいではありません。これは、サブクエリで rownum 値を偽造する必要があるためです。

基本的なアプローチは、予約テーブルの適切なサブセットをそれ自体に 1 つオフセットして結合することです。

アイテム 42 の予約の基本的なリストを、予約時間順に並べたものを次に示します。予約時間順であるとは限らないため、booking_id で注文することはできません。(2 つの既存の予約の間に新しい予約を挿入しようとしているのですね?) http://sqlfiddle.com/#!2/62383/9/0

  SELECT @aserial := @aserial+1 AS rownum,
         booking.*
    FROM booking,
         (SELECT @aserial:= 0) AS q
   WHERE item = 42
   ORDER BY startdate, enddate

これは、それ自体に結合されたサブセットです。秘訣は ですa.rownum+1 = b.rownum。これは、各行を予約テーブル サブセット内の直後の行に結合します。 http://sqlfiddle.com/#!2/62383/8/0

SELECT a.booking_id, a.startdate asta, a.enddate aend, 
                     b.startdate bsta, b.enddate bend 
  FROM (
      SELECT @aserial := @aserial+1 AS rownum,
             booking.*
        FROM booking,
             (SELECT @aserial:= 0) AS q
       WHERE item = 42
       ORDER BY startdate, enddate
       ) AS a
  JOIN (
      SELECT @bserial := @bserial+1 AS rownum,
             booking.*
        FROM booking,
             (SELECT @bserial:= 0) AS q
       WHERE item = 42
       ORDER BY startdate, enddate
       ) AS b ON a.rownum+1 = b.rownum

これもまた、各予約 (最後の予約を除く) とそれに続く時間数を示しています。 http://sqlfiddle.com/#!2/62383/15/0

SELECT a.booking_id, a.startdate, a.enddate, 
       TIMESTAMPDIFF(HOUR, a.enddate, b.startdate) gaphours 
  FROM (
      SELECT @aserial := @aserial+1 AS rownum,
             booking.*
        FROM booking,
             (SELECT @aserial:= 0) AS q
       WHERE item = 42
       ORDER BY startdate, enddate
       ) AS a
  JOIN (
      SELECT @bserial := @bserial+1 AS rownum,
             booking.*
        FROM booking,
             (SELECT @bserial:= 0) AS q
       WHERE item = 42
       ORDER BY startdate, enddate
       ) AS b ON a.rownum+1 = b.rownum

したがって、最も早い 12 時間スロットの開始時刻と終了時刻を探している場合は、その結果セットを使用してこれを行うことができます: http://sqlfiddle.com/#!2/62383/18/0

SELECT MIN(enddate) startdate, MIN(enddate) + INTERVAL 12 HOUR as enddate
   FROM (
    SELECT a.booking_id, a.startdate, a.enddate, 
           TIMESTAMPDIFF(HOUR, a.enddate, b.startdate) gaphours 
      FROM (
          SELECT @aserial := @aserial+1 AS rownum,
                 booking.*
            FROM booking,
                 (SELECT @aserial:= 0) AS q
           WHERE item = 42
           ORDER BY startdate, enddate
           ) AS a
      JOIN (
          SELECT @bserial := @bserial+1 AS rownum,
                 booking.*
            FROM booking,
                 (SELECT @bserial:= 0) AS q
           WHERE item = 42
           ORDER BY startdate, enddate
           ) AS b ON a.rownum+1 = b.rownum
    ) AS gaps
    WHERE gaphours >= 12
于 2013-10-22T22:50:39.057 に答える
1

これがクエリです。必要な日付、明らかな条件が返されます-テーブルには予約がいくつかあるはずですが、質問からわかるように-このチェックを行います:

SELECT min(enddate)
FROM
(
    select a.enddate from table4 as a
    where
        a.item=42 
    and
        DATE_ADD(a.enddate, INTERVAL 1 day) <= ifnull(
            (select min(b.startdate)
            from table4 as b where b.startdate>=a.enddate and a.item=b.item),
        a.enddate)
    and
        a.enddate>=now()
    union all
    select greatest(ifnull(max(enddate), now()),now()) from table4
) as q

に変更INTERVAL 1 dayしますINTERVAL ### hour

于 2013-10-22T23:01:12.073 に答える