2

PostgreSql 9.2 予約テーブルは次のように定義されます

CREATE EXTENSION btree_gist;
CREATE TABLE schedule (
  id serial primary key,
  during tsrange not null,
  EXCLUDE USING gist (during WITH &&)
);

休日は表に記載

CREATE TABLE holiday ( day primary key );

勤務時間は平日8時~18時、予約は30分間隔のみ。勤務時間中の予約のみを許可するように during 値に制約を追加する方法:

  1. tsrange の開始日と終了日は常に同じです。
  2. 開始日と終了日を土曜日と日曜日にすることはできません
  3. 開始日と終了日は祝日テーブルに表示できません
  4. 開始時間は 8:00 、 8:30 、 9:00 、 9:30 、 ... 16:00 、 16:30 、 17:00 、または 17:30 のみにすることができます。
  5. 終了時間は、8:30、9:00、9:30、... 16:00、16:30、17:00、17:30、または 18:00 のみにすることができます。

これらの制約またはその一部をこのテーブルに追加することは合理的ですか? はいの場合、どのように追加しますか? これが役立つ場合は、集計表の構造を変更できます。

4

2 に答える 2

4

単純なCHECK制約で、項目3を除くすべてを解決できます。

専用の範囲機能 lower(anysrange)upper(anyrange)使用して、範囲の下限/上限にアクセスします。

1.)tsrangeの開始日と終了日は常に同じです。

CONSTRAINT schedule_same_day
CHECK (lower(during)::date = upper(during)::date)

2.)開始日と終了日を土曜日と日曜日にすることはできません

単純な式isodowではなくdow、を使用してください。

CONSTRAINT schedule_no weekend
CHECK (EXTRACT(ISODOW FROM lower(during)) < 6)  -- upper on same day

3.)開始日と終了日を祝日の表に表示することはできません

唯一の例外:これには、次のようなトリガーが必要です。

CREATE OR REPLACE FUNCTION trg_during_no_holy()
  RETURNS trigger AS
$func$
BEGIN

IF EXISTS (SELECT 1 FROM holiday WHERE day = lower(NEW.during)) THEN
    RAISE EXCEPTION 'Day too holy: %', lower(NEW.during);
END IF;

RETURN NEW;

END
$func$ LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER insupbef_holycheck
  BEFORE INSERT OR UPDATE
  ON schedule
  FOR EACH ROW
  EXECUTE PROCEDURE trg_during_no_holy();

4.)開始時間は8:00、8:30、9:00、9:30、... 16:00、16:30、17:00、または17:30のみ
です。5。)終了時間は8:30、9:00、9:30、... 16:00、16:30、17:00、17:30、または18:00のみ

CONSTRAINT schedule_8_inc_to_18_exc_half_hours
 CHECK (lower(during)::time BETWEEN time '8:00'AND time '17:30' -- time range
    AND upper(during)::time BETWEEN time '8:30'AND time '18:00'
    AND EXTRACT(MINUTE FROM lower(during)) IN (0, 30) -- only :00 or :30
    AND EXTRACT(MINUTE FROM upper(during)) IN (0, 30)
    AND lower_inc(during)          -- lower bound always incl.
    AND upper_inc(during) = FALSE  -- upper bound always excl.
)

コメントの追加の質問

秒と小数秒を0のみに制限するにはどうすればよいですか?

最も簡単な方法:最初に列にこのデータ型をキャストするtimestamp(0)timestamptz(0)、このデータ型を使用します。ここでマニュアルを引用します:

time、、timestampおよび は、秒フィールドに保持される小数桁数を指定intervalするオプションの精度値を受け入れます。p

于 2012-11-25T22:24:46.573 に答える
1

checkテーブル定義を変更し、いくつかの制約を追加する必要があります。

CREATE TABLE schedule (
  id serial primary key,
  during tsrange not null check(
    (lower(during)::date = upper(during)::date) and 
    (date_trunc('hour', upper(during)) + INTERVAL '30 min' * ROUND(date_part('minute', upper(during)) / 30.0) = upper(during)) and
    (date_trunc('hour', lower(during)) + INTERVAL '30 min' * ROUND(date_part('minute', lower(during)) / 30.0) = lower(during)) and
    (lower(during)::time >= '8:00'::time and upper(during)::time <= '18:00'::time) and
    (date_part('dow', lower(during)) in (1,2,3,4,5) and date_part('dow', upper(during)) in (1,2,3,4,5))
  ),
  EXCLUDE USING gist (during WITH &&)
);

チェックはこの順番で

  • 開始日と終了日が同じ
  • 開始/終了は 30 分の境界上にある必要があります
  • および 8:00 ~ 18:00 の間
  • 平日のみ

テーブルに何かが必要ですholiday: 休日の値 ('2012-11-28') に挿入します。

check他のテーブルを参照できないため、トリガー関数が必要です (すべてのチェックをこの関数に入れる、つまり 1 か所にまとめておく方がよい場合があります)。

create function holiday_check() returns trigger language plpgsql stable as $$
begin
    if exists (select * from holiday where day in (lower(NEW.during)::date, upper(NEW.during)::date)) then
        raise exception 'public holiday';
    else
        return NEW;
    end if;
end;
$$;

insert次に、 /の前にトリガーを作成する必要がありますupdate

create trigger holiday_check_i before insert on schedule for each row execute procedure holiday_check();
create trigger holiday_check_u before update on schedule for each row execute procedure holiday_check();

最後に、いくつかのテスト:

-- OK
insert into schedule(during) values (tsrange('2012-11-26 08:00', '2012-11-26 09:00'));
INSERT 0 1

-- out of business hours
insert into schedule(during) values (tsrange('2012-11-26 04:00', '2012-11-26 05:00'));
ERROR:  new row for relation "schedule" violates check constraint "schedule_during_check"
DETAIL:  Failing row contains (12, ["2012-11-26 04:00:00","2012-11-26 05:00:00")).

-- End time can be only 8:30, 9:00, 9:30, ... 16:00, 16:30, 17:00, 17:30 or 18:00 exclusive
insert into schedule(during) values (tsrange('2012-11-26 08:00', '2012-11-26 09:10'));
ERROR:  new row for relation "schedule" violates check constraint "schedule_during_check"
DETAIL:  Failing row contains (13, ["2012-11-26 08:00:00","2012-11-26 09:10:00")).

-- Start time can be only 8:00 , 8:30, 9:00, 9:30, ... 16:00, 16:30, 17:00 or 17:30 inclusive
insert into schedule(during) values (tsrange('2012-11-26 11:24', '2012-11-26 13:00'));
ERROR:  new row for relation "schedule" violates check constraint "schedule_during_check"
DETAIL:  Failing row contains (14, ["2012-11-26 11:24:00","2012-11-26 13:00:00")).

-- holiday
insert into schedule(during) values (tsrange('2012-11-28 10:00', '2012-11-28 13:00'));
ERROR:  public holiday
于 2012-11-25T23:03:54.550 に答える