4

予約テーブルには、予約の開始日、開始時間、および期間が含まれています。開始時間は、就業時間の30分刻みで8:00..就業日の18:00です。期間も1日で30分刻みです。

CREATE TABLE reservation (
  startdate date not null,  -- start date
  starthour numeric(4,1) not null , -- start hour 8 8.5 9 9.5  ..  16.5 17 17.5
  duration  Numeric(3,1) not null, -- duration by hours 0.5 1 1.5 .. 9 9.5 10
  primary key (startdate, starthour)
);

テーブル構造は必要に応じて変更できます。

予約されていないテーブルで最初の無料の30分を見つける方法は?テーブルにが含まれている場合の式

startdate   starthour  duration 
14          9           1              -- ends at 9:59
14          10          1.5            -- ends at 11:29, e.q there is 30 minute gap before next
14          12          2
14          16          2.5

結果は次のようになります。

starthour  duration
11.5       0.5

おそらくPostgreSql9.2ウィンドウ関数を使用して、開始時間が前の行の開始時間+期間よりも大きい最初の行を検索する必要が
あります。この情報を返すselectステートメントの記述方法は?

4

2 に答える 2

9

Postgres 9.2には範囲タイプがあるので、それらを使用することをお勧めします。

create table reservation (reservation tsrange);
insert into reservation values 
('[2012-11-14 09:00:00,2012-11-14 10:00:00)'), 
('[2012-11-14 10:00:00,2012-11-14 11:30:00)'), 
('[2012-11-14 12:00:00,2012-11-14 14:00:00)'), 
('[2012-11-14 16:00:00,2012-11-14 18:30:00)');

ALTER TABLE reservation ADD EXCLUDE USING gist (reservation WITH &&);

「EXCLUDEUSINGgist」は、重複するエントリの挿入を禁止するインデックスを作成します。次のクエリを使用して、ギャップ(vyegorovのクエリのバリエーション)を見つけることができます。

with gaps as (
  select 
    upper(reservation) as start, 
    lead(lower(reservation),1,upper(reservation)) over (ORDER BY reservation) - upper(reservation) as gap 
  from (
    select * 
    from reservation 
    union all values 
      ('[2012-11-14 00:00:00, 2012-11-14 08:00:00)'::tsrange), 
      ('[2012-11-14 18:00:00, 2012-11-15 00:00:00)'::tsrange)
  ) as x
) 
select * from gaps where gap > '0'::interval;

「unionallvalues」は非稼働時間をマスクするため、午前8時から午後18時までのみ予約できます。

結果は次のとおりです。

        start        |   gap    
---------------------+----------
 2012-11-14 08:00:00 | 01:00:00
 2012-11-14 11:30:00 | 00:30:00
 2012-11-14 14:00:00 | 02:00:00

ドキュメントリンク:-http: //www.postgresql.org/docs/9.2/static/rangetypes.html「範囲タイプ」-https://wiki.postgresql.org/images/7/73/Range-types-pgopen- 2012.pdf

于 2012-11-15T00:26:07.453 に答える
1

おそらく最良のクエリではありませんが、それはあなたが望むことをします:

WITH
times AS (
    SELECT startdate sdate,
        startdate + (floor(starthour)||'h '||
           ((starthour-floor(starthour))*60)||'min')::interval shour,
        startdate + (floor(starthour)||'h '||
           ((starthour-floor(starthour))*60)||'min')::interval 
           + (floor(duration)||'h '||
             ((duration-floor(duration))*60)||'min')::interval ehour
      FROM reservation),
gaps AS (
    SELECT sdate,shour,ehour,lead(shour,1,ehour)
       OVER (PARTITION BY sdate ORDER BY shour) - ehour as gap
      FROM times)
SELECT * FROM gaps WHERE gap > '0'::interval;

いくつかのメモ:

  1. イベントの時間とデータを分離しない方が良いでしょう。必要な場合は、標準タイプを使用してください。
  2. 標準タイプを使用できない場合は、numeric時間をtime形式に変換する関数を作成してください。
于 2012-11-14T21:38:15.373 に答える