2

我有一个由三个值组成的表

  1. 参与者ID
  2. 课程事件ID
  3. 标记

每人courseevent只限15人

如何使用 Oracle 进行检查?

4

5 回答 5

3

这个问题最重要的方面是让它在多用户环境中工作。

Oracle 只允许 READ COMMITTED 和 SERIALIZED 隔离级别。没有幻读或脏读,也没有“偷看”未提交会话的机制。 了解更多

这意味着这个声明

select courseevent, count(*) 
from courseparticpants
group by courseevent;

将显示已提交的记录数。如果您继续插入记录,您仍然可以插入第十六次预订,如果其他人在此期间提交了他们的工作。相反,当实际上有人要删除一行时,您可能会认为课程已经满了。

要控制这一点,您需要序列化对courseparticpants表的访问,以便一次只有一个会话可以将记录插入其中。有多种方法可以做到这一点,但最安全的是:

lock table courseparticpants exclusive nowait;

如果您未能获得锁定,您就知道另一个会话已经在处理它。否则,您可以运行您的计数,插入一个新的预订并执行任何其他需要的操作,并确信您的规则没有被违反。

重要的是不要因为太锁而冻结在锁上,原因很明显:没有其他人可以在桌子上做他们的工作。一个稍微不那么突兀的机制是锁定父表中的相关记录;我没有首先提出这个建议,因为我不想对您的数据模型做出假设。

select whatever
from courseevents
where courseevent = :p1
for update nowait;

这将允许其他会议为另一个活动预订参与者。 了解更多

这两种解决方案都需要编写一个程序单元——比如在 PL/SQL 中——来管理事务。

“有没有可能在约束条件下解决这个问题?”

不,Oracle 不允许在其 CHECK 约束中使用 SQL。标准 SQL 有断言的概念,但 Oracle 没有实现它们。

一种可能的解决方案是在participantid内进行计数courseevent,因此您可以强制执行检查约束

check ( participantid <= 15)

但是,您仍然需要执行所有锁定操作才能获得当前参与者数量的准确数字,以确保您n+1是正确的。

于 2013-03-01T06:46:49.970 回答
0
select count(*)
from blah, blah, blah

为您提供现有记录的数量。

于 2013-03-01T04:01:28.473 回答
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

请注意,当您提交事务时会检查约束,因此在最后一个示例中,任何参与者都不会注册。

于 2013-03-02T14:09:26.327 回答
0

这显示了超过 15 个事件的参与者。

SELECT participant, COUNT(DISTINCT courseevent) F
FROM Table
GROUP BY participant
HAVING COUNT(DISTINCT courseevent) > 15
于 2013-03-01T04:12:44.577 回答
0
INSERT INTO MyTable(Col1, Col2, Col3)
    SELECT 'Val1', 'Val2', 'Val3'
      FROM DUAL
     WHERE (SELECT COUNT(*) FROM MyTable WHERE condition) < 15;
于 2013-03-01T04:13:49.550 回答