Sql 在插入新数据集之前,是否获取表中已存在事件的行数?

Sql 在插入新数据集之前,是否获取表中已存在事件的行数?,sql,oracle,insert,Sql,Oracle,Insert,我有一个由三个值组成的表 参加者的身份证 课程事件的ID 做记号 每个课程只允许15人参加 如何使用Oracle对此进行检查 select count(*) from blah, blah, blah 提供现有记录的数量 这显示了超过15项活动的参与者 SELECT participant, COUNT(DISTINCT courseevent) F FROM Table GROUP BY participant HAVING COUNT(DISTINCT courseevent) >

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

参加者的身份证 课程事件的ID 做记号 每个课程只允许15人参加

如何使用Oracle对此进行检查

select count(*)
from blah, blah, blah

提供现有记录的数量

这显示了超过15项活动的参与者

SELECT participant, COUNT(DISTINCT courseevent) F
FROM Table
GROUP BY participant
HAVING COUNT(DISTINCT courseevent) > 15

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

Oracle只允许读取提交和序列化隔离级别。没有虚读或脏读,也没有窥视未提交会话的机制

也就是说这句话

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不允许在其检查约束中使用SQL。标准SQL有断言的概念,但Oracle没有实现它们

一种可能的解决方案是在CourseeEvent中设置participantid计数,这样就可以强制执行检查约束

check ( participantid <= 15)

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

> P>常规表约束只考虑孤立的行,但您的要求是考虑一组行。 这是一个相当复杂的解决方案,它使用物化视图约束来实现需求。 可以将其视为在结果集中的列上定义约束

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);

请注意,在提交事务时会检查约束,因此在上一个示例中,所有参与者都不会注册。

这是正确的,但您应该只从一个BLAH中进行选择。还考虑添加触发器。触发器应在插入和回滚之前选择事件的参与者计数(如果在我的国家/地区已经有15.5)WHISPER@scotch-可能是这样,但在堆栈溢出的国家,使用句子大小写被认为是礼貌的。你的答案太简单了。什么时候数数?插入之前或之后?如果两个用户添加了第15个参与者呢?如果您希望,您可以创建自己的用户定义函数/触发器,该函数/触发器只需查询目标表中的COUNT*,如果大于14,您可以引发异常。指向SQL Server文档的链接并不总是与oracle问题相关。oracle不允许在检查约束中使用用户定义的函数,即使是确定性函数。处理序列化的一种不太全面的方法是使用DBMS_Lock,通过调用DBMS_Lock为courseevent构造一个唯一的锁名。Allocate_Uniquelockname=>to_charcourseevent,'CPFM000000000000'。。。等等。@Scotch-因为触发器不能解决多用户方面的问题。@davidardridge-我同意这是一个选项,但我针对这个问题定制了我的答案,我怀疑这是课程作业。DBMS_锁在这种情况下会有点高性能,如果只是因为它不是默认授予的。当然,额外的作业学分!没有什么比解释为什么你的解决方案在赢得朋友和影响他人方面比老师更好了更好的了。
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);
-- 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