會議室預定系統實踐(輕鬆解放開發)-PostgreSQLtsrange(時間範圍型別)+排他約束
標籤
PostgreSQL , tsrange , 範圍 , exclude using , 排他約束 , btree_gist , 會議室預定 , 時間重疊 , 空間重疊
背景
PostgreSQL 範圍、陣列、空間型別(range, array, geometry),都有交叉屬性,例如時間範圍:7點到9點,8點到9點,這兩個內容是有重疊部分的。例如陣列型別:[1,2,3]和[2,4,5]是有交叉部分的。例如空間型別也有交叉的屬性。
那麼在設計時,實際上業務上會有這樣的約束,不允許物件有相交。
例如會議室預定系統,不允許兩個人預定的會議室時間交叉,否則就有可能一個會議室在某個時間段被多人共享了,業務上是不允許的。
那麼如何做到這樣的約束呢?
PostgreSQL 提供了exclude約束,可以實現這個需求。
exclude 約束的語法
EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] |
exclude_element in an EXCLUDE constraint is:
{ column_name | ( expression ) } [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]
exclude 約束常用的操作符
範圍、陣列、空間型別的相交操作符如下:
postgres=# do &&
List of operators
Schema | Name | Left arg type | Right arg type | Result type | Description
------------+------+---------------+----------------+-------------+----------------------------------
pg_catalog | && | anyarray | anyarray | boolean | overlaps
pg_catalog | && | anyrange | anyrange | boolean | overlaps
pg_catalog | && | box | box | boolean | overlaps
pg_catalog | && | circle | circle | boolean | overlaps
pg_catalog | && | inet | inet | boolean | overlaps (is subnet or supernet)
pg_catalog | && | polygon | polygon | boolean | overlaps
pg_catalog | && | tinterval | tinterval | boolean | overlaps
pg_catalog | && | tsquery | tsquery | tsquery | AND-concatenate
public | && | integer[] | integer[] | boolean | overlaps
(9 rows)
會議室預定系統的例子
1、建立btree_gist外掛.
postgres=# create extension btree_gist;
CREATE EXTENSION
2、建立會議室預定表
postgres=# create table t_meeting (
roomid int, -- 會議室ID
who int, -- 誰定了這個會議室
ts tsrange, -- 時間範圍
desc text, -- 會議內容描述
exclude using gist (roomid with = , ts with &&) -- 排他約束,同一個會議室,不允許有時間範圍交叉的記錄
);
CREATE TABLE
3、預定會議室,如果同一個會議室輸入的時間不允許預定(有交叉),則自動報錯。實現強約束。
postgres=# insert into t_meeting values (1, 1, $$[`2017-01-01 07:00:00`, `2017-01-01 08:00:00`)$$);
INSERT 0 1
postgres=# insert into t_meeting values (1,1,$$[`2017-01-01 07:00:00`, `2017-01-01 08:00:00`)$$);
ERROR: conflicting key value violates exclusion constraint "t_meeting_roomid_ts_excl"
DETAIL: Key (roomid, ts)=(1, ["2017-01-01 07:00:00","2017-01-01 08:00:00")) conflicts with existing key (roomid, ts)=(1, ["2017-01-01 07:00:00","2017-01-01 08:00:00")).
postgres=# insert into t_meeting values (2,1,$$[`2017-01-01 07:00:00`, `2017-01-01 08:00:00`)$$);
INSERT 0 1
postgres=# insert into t_meeting values (1,1,$$[`2017-01-01 09:00:00`, `2017-01-01 10:00:00`)$$);
INSERT 0 1
postgres=# insert into t_meeting values (1,1,$$[`2017-01-01 09:00:00`, `2017-01-01 11:00:00`)$$);
ERROR: conflicting key value violates exclusion constraint "t_meeting_roomid_ts_excl"
DETAIL: Key (roomid, ts)=(1, ["2017-01-01 09:00:00","2017-01-01 11:00:00")) conflicts with existing key (roomid, ts)=(1, ["2017-01-01 09:00:00","2017-01-01 10:00:00")).
postgres=# insert into t_meeting values (1,1,$$[`2017-01-01 08:00:00`, `2017-01-01 09:00:00`)$$);
INSERT 0 1
postgres=# select * from t_meeting order by roomid, ts;
roomid | who | ts
--------+-----+-----------------------------------------------
1 | 1 | ["2017-01-01 07:00:00","2017-01-01 08:00:00")
1 | 1 | ["2017-01-01 08:00:00","2017-01-01 09:00:00")
1 | 1 | ["2017-01-01 09:00:00","2017-01-01 10:00:00")
2 | 1 | ["2017-01-01 07:00:00","2017-01-01 08:00:00")
(4 rows)
4、查詢某個時間段還有哪些會議室能預定
會議室ID表,假設有50個會議室。
create table t_room (roomid int primary key);
insert into t_room select generate_series(1,50);
假設使用者要預定 某一天:7點到9點的會議室,這樣操作即可:
select roomid from t_room
except
select roomid from t_meeting where ts && $$[`2017-01-01 07:00:00`, `2017-01-01 09:00:00`)$$;
roomid
--------
14
3
4
16
42
50
19
13
40
46
18
34
39
7
35
43
23
36
29
30
28
8
24
32
10
33
9
45
22
49
48
38
37
5
12
31
11
27
20
44
41
6
21
15
47
17
26
25
(48 rows)
postgres=# explain (analyze,verbose,timing,costs,buffers) select roomid from t_room
except
select roomid from t_meeting where ts && $$[`2017-01-01 07:00:00`, `2017-01-01 09:00:00`)$$;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------
HashSetOp Except (cost=0.00..77.28 rows=2550 width=8) (actual time=0.074..0.085 rows=48 loops=1)
Output: "*SELECT* 1".roomid, (0)
Buffers: shared hit=3
-> Append (cost=0.00..70.88 rows=2562 width=8) (actual time=0.013..0.058 rows=53 loops=1)
Buffers: shared hit=3
-> Subquery Scan on "*SELECT* 1" (cost=0.00..61.00 rows=2550 width=8) (actual time=0.012..0.029 rows=50 loops=1)
Output: "*SELECT* 1".roomid, 0
Buffers: shared hit=1
-> Seq Scan on public.t_room (cost=0.00..35.50 rows=2550 width=4) (actual time=0.010..0.016 rows=50 loops=1)
Output: t_room.roomid
Buffers: shared hit=1
-> Subquery Scan on "*SELECT* 2" (cost=1.44..9.88 rows=12 width=8) (actual time=0.018..0.019 rows=3 loops=1)
Output: "*SELECT* 2".roomid, 1
Buffers: shared hit=2
-> Bitmap Heap Scan on public.t_meeting (cost=1.44..9.76 rows=12 width=4) (actual time=0.018..0.018 rows=3 loops=1)
Output: t_meeting.roomid
Recheck Cond: (t_meeting.ts && `["2017-01-01 07:00:00","2017-01-01 09:00:00")`::tsrange)
Heap Blocks: exact=1
Buffers: shared hit=2
-> Bitmap Index Scan on t_meeting_roomid_ts_excl (cost=0.00..1.44 rows=12 width=0) (actual time=0.010..0.010 rows=4 loops=1)
Index Cond: (t_meeting.ts && `["2017-01-01 07:00:00","2017-01-01 09:00:00")`::tsrange)
Buffers: shared hit=1
Planning time: 0.123 ms
Execution time: 0.172 ms
(24 rows)
速度槓槓的。開發也方便了。
小結
使用PostgreSQL,時間範圍型別、exclude約束,很好的幫助業務系統實現會議室預定的強約束。
使用except語法,很方便的找到需要預定的時間段還有那些會議室是空閒的。
開不開心,解放開發人員的大腦。
參考
https://www.postgresql.org/docs/10/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
相關文章
- layui laydate日期時間範圍,時間預設設定為23:59:59UI
- 會議預約管理資訊系統
- C# 泛型 引用型別約束 值型別約束C#泛型型別
- 資料型別範圍資料型別
- 使用 Meteor 輕鬆開發實時網站網站
- 配送交付時間輕量級預估實踐
- element-ui 時間選擇器設定時間選擇範圍UI
- PHP7型別約束PHP型別
- python - 生成時間範圍Python
- JS判定一個給定的時間在某個時間範圍內JS
- JS實現檢查給定時間範圍是否在每天的某個時間段內JS
- JS判定一個給定的時間區間在哪些時間段範圍內JS
- Oracle日期時間範圍查詢Oracle
- uniapp 周選擇範圍時間APP
- Laravel admin 如何生成 開始時間和結束時間範圍之內的篩選條件 (2 個欄位)Laravel
- [譯]Kotlin泛型中何時該用型別形參約束?Kotlin泛型型別
- 量化合約系統開發穩定版,量合約系統開發(成熟及案例)
- 華為雲會議,輕鬆實現遠端智慧辦公
- SQL教程——常見的約束型別SQL型別
- Oracle constraints type 約束型別OracleAI型別
- PHP中的型別約束介紹PHP型別
- Redis輕鬆實現秒殺系統Redis
- 如何實現完美會議 可立享帶你盡享輕鬆會議新主張
- 時間同步協議NTP - 原理&實踐協議
- 輕鬆使用WebWorker,解放耗時較大的演算法程式碼Web演算法
- 網路會議室解決方案系統部署
- 預設值+TS型別約束提高資料處理成功率型別
- Oracle預定義的21個系統異常型別Oracle型別
- PLM系統應用範圍
- 新媒體圖文分發系統,解放雙手,輕鬆運營30+自媒體平臺
- 秒合約開發(穩定版)丨秒合約系統開發(開發案例)丨秒合約系統原始碼詳情原始碼
- Oracle定義約束 外來鍵約束Oracle
- 用Redis輕鬆實現秒殺系統Redis
- 用 Redis 輕鬆實現秒殺系統Redis
- lubridate—輕鬆處理日期時間
- 用regRange輕易實現特定數字範圍的正則驗證,如時間,IP等 (轉)
- 什麼是IDO預售系統開發?IDO預售合約系統開發原理分析
- 時間型別型別