|
|
谜题6 预订旅馆房间
这篇是纯转帖,里面有个实现表约束的方法很巧妙,值得学习。
说的是有一张表存储每个旅馆房间的预定情况:
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
arrival_date DATE NOT NULL, ---- 入住日期
departure_date DATE NOT NULL, ---- 离开日期
guest_name CHAR(30) NOT NULL,
PRIMARY KEY (room_nbr, arrival_date),
CHECK (departure_date >= arrival_date)
);
现在要实现的是每两条记录之间不允许出现入住时间区间的重叠。
Answer #1
这是别的数据库的方法,ORACLE中不支持。
One solution requires a product to have the capability of using fairly
complex SQL in the CHECK() clause, so you will find that a lot of
implementations will not support it.
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
arrival_date DATE NOT NULL,
departure_date DATE NOT NULL,
guest_name CHAR(30),
PRIMARY KEY (room_nbr, arrival_date),
CHECK (departure_date >= arrival_date),
CHECK (NOT EXISTS
(SELECT *
FROM Hotel AS H1, Hotel AS H2
WHERE H1.room_nbr = H2.room_nbr
AND H1.arrival_date
BETWEEN H2.arrival_date AND
H2.departure_date)));
Answer #2
Another solution is to redesign the table, giving a row for each day and
each room, thus:
CREATE TABLE Hotel
(room_nbr INTEGER NOT NULL,
occupy_date DATE NOT NULL,
guest_name CHAR(30) NOT NULL,
PRIMARY KEY (room_nbr, occupy_date, guest_name));
如果住10天就会有10条记录,这个不推荐。
Answer #3
Lothar Flatz, an instructor for Oracle Software Switzerland, made the
objection that the clause "H1.arrival_date BETWEEN
H2.arrival_date AND H2.depatures" does not allow for a guest name
to arrive the same day another guest name leaves.
Since Oracle cannot put subqueries into CHECK() constraints and
triggers would not be possible because of the mutating table problem, he
used a VIEW that has a WITH CHECK OPTION to enforce the occupancy
constraints:
CREATE VIEW HotelStays (room_nbr, arrival_date,
departure_date, guest_name)
AS SELECT room_nbr, arrival_date, departure_date,
guest_name
FROM Hotel AS H1
WHERE NOT EXISTS
(SELECT *
FROM Hotel AS H2
WHERE H1.room_nbr = H2.room_nbr
AND H2.arrival_date < H1.arrival_date
PUZZLE 6 HOTEL RESERVATIONS 23
AND H1.arrival_date < H2.departure_date)
WITH CHECK OPTION;
For example,
INSERT INTO HotelStays
VALUES (1, '2008-01-01', '2008-01-03', 'Coe');
COMMIT;
INSERT INTO HotelStays
VALUES (1, '2008-01-03', '2008-01-05', 'Doe');
will give a WITH CHECK OPTION clause violation on the second INSERT
INTO statement. This is a good trick for getting table-level constraints in
a table on products without full SQL-92 features.
最后一个方法是个很好的技巧,他使用了WITH CHECK OPTION的视图来实现约束。注意对表的插入和修改都必须改成对视图操作。但是读数据还是从表来,才不会无端多了个NOT EXISTS的开销。
如果不用这个方法,那就得用触发器或者在应用中写校验代码,全都是复杂而且低效的方法。 |
|