我有一个由三个值组成的表
对于每个courseevent
,只允许15个人
如何使用Oracle检查?
答案 0 :(得分:3)
此问题最重要的方面是使其在多用户环境中工作。
Oracle仅允许READ COMMITTED和SERIALIZED隔离级别。没有幻像或脏读,也没有在未提交的会话中“窥视”的机制。 Find out more
这意味着这句话
select courseevent, count(*)
from courseparticpants
group by courseevent;
将显示已提交的记录数。如果您继续插入记录,您仍然可以插入第16个预订,如果其他人在此期间承诺他们的工作。相反,当事实上有人要删除一行时,你可能会认为课程已经满了。
要控制此操作,您需要序列化对courseparticpants
表的访问权限,以便一次只能有一个会话将记录插入其中。有多种方法可以做到这一点,但最安全的是:
lock table courseparticpants exclusive nowait;
如果你没有获得锁定,你知道另一个会话已经在进行。否则,您可以运行您的计数,插入新的预订并执行其他所需的操作,并确信您的规则不会被破坏。
重要的是不要为了过于锁定而冻结锁,原因显而易见:没有其他人可以在桌子上做他们的工作。稍微不那么突兀的机制是将相关记录锁定在父表中;我没有先提出这个问题,因为我不想对你的数据模型做出假设。
select whatever
from courseevents
where courseevent = :p1
for update nowait;
这将允许其他会话预订其他活动的参与者。 Find out more
这两种解决方案都需要编写程序单元(比如PL / SQL)来管理事务。
“是否有可能通过约束来解决这个问题?”
不,Oracle不允许在其CHECK约束中使用SQL。标准SQL具有ASSERTIONS的概念,但Oracle尚未实现它们。
一种可能的解决方案是在participantid
内使courseevent
计数,以便您可以强制执行检查约束
check ( participantid <= 15)
但是,您仍然需要执行所有锁定操作以获取当前参与者数量的准确数字,以便n+1
正确无误。
答案 1 :(得分:0)
select count(*)
from blah, blah, blah
为您提供现有记录的数量。
答案 2 :(得分:0)
这显示超过15个活动的参与者。
SELECT participant, COUNT(DISTINCT courseevent) F
FROM Table
GROUP BY participant
HAVING COUNT(DISTINCT courseevent) > 15
答案 3 :(得分:0)
INSERT INTO MyTable(Col1, Col2, Col3)
SELECT 'Val1', 'Val2', 'Val3'
FROM DUAL
WHERE (SELECT COUNT(*) FROM MyTable WHERE condition) < 15;
答案 4 :(得分:0)
常规表约束仅隔离各个行,但您的要求是一起考虑行。 这是一个相当复杂的解决方案,它使用物化视图约束来实现需求。 您可以将此视为定义结果集中列的约束。
create table course_participants(
course varchar2(20) not null
,participant varchar2(20) not null
,constraint course_participants_pk primary key(course, participant)
);
-- Need this for fast refreshable mview
create materialized view log
on course_participants
with rowid(course, participant)
including new values;
-- A materialized view with a count of participants per course
create materialized view course_parts_max_mv
refresh fast on commit
as
select course
,count(*) as participants
from course_participants
group
by course;
-- This is where you perform the check.
-- I've used 2 participants to make the example easier
alter materialized view course_parts_max_mv
add constraint too_many_participants check(participants <= 2);
上面的DDL创建了一个表和一个物化视图。物化视图将包含每个课程的一行以及参与者的nr。诀窍是,我们现在可以在物化视图上声明它,而不是在基表上声明约束。
-- One participant is ok!
insert into course_participants values('Oracle', 'Alfred');
commit;
-- Two participants are ok!
insert into course_participants values('Englis speling', 'Benjamin');
insert into course_participants values('Englis speling', 'Charles');
commit;
-- This will fail, because the count(*) for 'Economics' will return 3
insert into course_participants values('Economics', 'Alfred');
insert into course_participants values('Economics', 'Benjamin');
insert into course_participants values('Economics', 'Charles');
commit;
ORA-12008: error in materialized view refresh path
ORA-02290: check constraint (RNBN.TOO_MANY_PARTICIPANTS) violated
请注意,当您提交交易时会检查约束,因此在最后一个示例中,没有参与者会被注册。