5

PostgreSql の予約テーブルで最初の空き時間を見つける方法の優れた回答から選択してください

create table reservation (during tsrange,
 EXCLUDE USING gist (during WITH &&)
 );

指定された日時 (2012-11-17 8: 以下のサンプル) から始まるスケジュールのギャップを見つけるために使用されます。土曜、日曜、祝日も検索します。祝日は表に定義されています

create table pyha ( pyha date primary key)

土日祝日も除外するには?

次のようなクエリのために予約された空き時間をハードコーディングする

with gaps as (
  select
    upper(during) as start,
    lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap
  from (
    select during
    from reservation
   union all values
     ('(,2012-11-17 8:)'::tsrange), -- given date and hour from which to find free work time
     ('[2012-11-17 0:,2012-11-18 24:)'::tsrange), -- exclude saturday
     ('[2012-11-18 0:,2012-11-19 8:)'::tsrange),  -- exclude sunday
     ('[2012-11-19 18:,2012-11-20 8:)'::tsrange),
     ('[2012-11-20 18:,2012-11-21 8:)'::tsrange),
     ('[2012-11-21 18:,2012-11-22 8:)'::tsrange),
     ('[2012-11-22 18:,2012-11-23 8:)'::tsrange),
     ('[2012-11-23 18:,2012-11-24 24:)'::tsrange),
     ('[2012-11-24 0:,2012-11-25 24:)'::tsrange), -- exclude saturday
     ('[2012-11-25 0:,2012-11-26 8:)'::tsrange)  -- exclude sunday
 ) as x
)
select *
  from gaps
where gap > '0'::interval
order by start

空き時間範囲ごとにユニオン内の個別の行が必要です。

指定された日付と時間から始まる稼働日と稼働時間 (8:00 .. 18:00) で空き時間を返す最良の方法はどれですか?

アップデート

回答で選択すると、常に 8:00 に空き時間が返されます。開始時間が 9 の場合、指定された開始日の指定された開始時間の前ではない空き時間を返す方法、たとえば 2012-11-19 9:00 の前ではないですか? 開始時間には、8、9、10、11、12、13、14、15、16、または 17 の値のみを指定できます

2012-11-19 8:00 が無料の場合でも、2012-11-19 9:00 を返す必要があります。2012 年 11 月 19 日の 9:00 に空き時間がなく、8:00 が後続の就業日の最初の空き時間である場合にのみ、8:00 を返す必要があります。

以下のクエリに示すように、2012-11-19 9:を 2 つの場所に追加してこれを修正しようとしましたが、このクエリは 2012-11-19 8:00 に空き時間を返します。2012-11-19 9:00 に空き時間を返すようにこれを修正するにはどうすればよいですか?

create table reservation (during tsrange,
 EXCLUDE USING gist (during WITH &&)
 );
create table pyha ( pyha date primary key);
with gaps as (
    select
        upper(during) as start,
        lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap
    from (
        select during
          from reservation
             where upper(during)>= '2012-11-19 9:'
       union all values
         ('(,2012-11-19 9:)'::tsrange)
        union all
        select
            unnest(case
                when pyha is not null then array[tsrange(d, d + interval '1 day')]
                when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')]
                else array[tsrange(d, d + interval '8 hours'),
                           tsrange(d + interval '18 hours', d + interval '1 day')]
            end)
        from generate_series(
            '2012-11-19'::timestamp without time zone,
            '2012-11-19'::timestamp without time zone+ interval '3 month',
            interval '1 day'
        ) as s(d)
        left join pyha on pyha = d::date
    ) as x
)

select start,
   date_part('epoch', gap) / (60*60) as hours
  from gaps
where gap > '0'::interval
order by start

Update2

更新された回答を試しましたが、間違ったデータが返されます。完全なテストケースは次のとおりです。

create temp table reservation  ( during tsrange ) on commit drop;
insert into reservation values(
'[2012-11-19 11:00:00,2012-11-19 11:30:00)'::tsrange );

with gaps as (
    select
        upper(during) as start,
        lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap
    from (
        select during
          from reservation
        union all
        select
            unnest(case
                when pyha is not null then array[tsrange(d, d + interval '1 day')]
                when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')]
                when d::date =  DATE'2012-11-19' then array[
                            tsrange(d, '2012-11-19 12:'),  -- must return starting at 12:00
                            tsrange(d + interval '18 hours', d + interval '1 day')]
                else array[tsrange(d, d + interval '8 hours'), 
                           tsrange(d + interval '18 hours', d + interval '1 day')]
            end)
        from generate_series(
            DATE'2012-11-19'::timestamp without time zone,
            DATE'2012-11-19'::timestamp without time zone+ interval '3 month',
            interval '1 day'
        ) as s(d) 
        left join pyha on pyha = d::date
    ) as x 
)

select start,
   date_part('epoch', gap) / (60*60) as tunde
  from gaps 
where gap > '0'::interval
order by start

観測された最初の行:

"2012-11-19 11:30:00"

期待される :

"2012-11-19 12:00:00"

直し方 ?

4

1 に答える 1

2

営業時間外をマスクするために、generate_series() 関数を使用できます。

with gaps as (
    select
        upper(during) as start,
        lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap
    from (
        select during
        from reservation
        union all
        select
            unnest(case
                when pyha is not null then array[tsrange(d, d + interval '1 day')]
                when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')]
                when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
                else array[tsrange(d, d + interval '8 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
            end)
        from generate_series(
            '2012-11-14'::timestamp without time zone, 
            '2012-11-14'::timestamp without time zone + interval '2 week', 
            interval '1 day'
        ) as s(d) 
        left join pyha on pyha = d::date
    ) as x 
)
select *
    from gaps
where gap > '0'::interval
order by start

いくつかのトリッキーな部分を説明しましょう。

  • pyha関数を使用できるため、土日の日付をテーブルに挿入する必要はありませんdate_part('dow', d)pyha祝日のみテーブルを使用してください。'dow' は、Sun または Sat に対してそれぞれ 0 または 6 を返します。
  • 祝日と土日は、1 つの間隔 (0..24) で表すことができます。平日は 2 つの間隔 (0..8) と (18..24) で表す必要があるため、unnest() と array[]
  • generate_series() 関数で開始日と長さを指定できます

質問への更新に基づいて、別のものを追加しましwhencase

when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]

アイデアは、開始日 ( d::date = '2012-11-14'): (0..9) と (18..24)の異なる間隔を生成することです。

于 2012-11-18T02:59:09.070 に答える