oracle(或任何关系)数据模型问题。有固定孩子数的家长?

时间:2010-07-28 14:36:21

标签: sql oracle plsql data-modeling

这是我遇到的一个特殊问题, 但我从来没有真正找到一个解决这个(看似)简单问题的简单方法。

如何确保给定的父母有固定数量的孩子?

1)例子。

如何确保某个课程只有50名学生注册??

create table class(
  class_id number primary key,
  class_name varchar2(50),
  class_attributes varchar2(50)
);

create table student(
    student_id number primary key,
    student_name varchar2(50),
    student_attributes varchar2(50)
);

create table class_student_asc(
    class_id number,
    student_id number,
    other_attributes varchar2(50),
    constraint pk_class_student_asc primary key (class_id,student_id),
    constraint fk_class_id foreign key (class_id) references class(class_id),
    constraint fk_student_id foreign key (student_id) references student(student_id)
);

这些是我所知道的实现。    让我知道您更喜欢哪一个,以及是否有更简单的方法来实现这一目标。

A)

在子表(class_student_asc)上使用触发器实现它。

在插入前查询同一个表,更新触发器以获取计数。    由于这会给出变异表错误,因此将其拆分为两个不同的语句级别    触发器(before-statement和after-statement)来实现结果..

http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936

b)中

在类表中包含count变量,并在将记录插入子表之前锁定更新的父记录。

所以,像..

create table class(
     class_id number primary key,
     class_name varchar2(50),
     class_attributes varchar2(50),
     class_count INTEGER,
     constraint chk_count_Students check (class_count <=5)
);

而不是为插入等公开表class_student_asc ...    编写一个程序,然后在所有应用程序中使用它。

procedure assign_new_student( 
        i_student_id number,
        i_class_id number)
   is 
   begin
       select class_count
         from class
         where class_id = i_class_id
           for update ; -- or for update nowait, if you want the other concurrent transaction to fail..

   insert into class_student_asc(
       class_id, student_id) 
     values (i_class_id,i_student_id);

   update class
      set class_count = class_count + 1
      where class_id = i_class_id;

   commit;
end assign_new_student;

c)中

当然,有一些用户有两个电子邮件地址的情况。 在这种情况下,电子邮件地址本身没有任何属性 这个表可以像

一样简单
create table user_table
          (
            user_id number,
            user_name varchar2(50),
            user_email_primary varchar2(50),
            user_email_secondary varchar2(50)
          );

但是,我们无法对上述问题扩展相同的方法.....因为列数和约束检查会减慢插入和更新的速度。此外,这意味着我们每次更改规则时都需要添加新列。

请建议。

3 个答案:

答案 0 :(得分:5)

对于Oracle,请考虑这种方法。

创建一个实体化视图,总结每个班级的学生人数。让mview在提交时刷新,并为mview添加一个约束,禁止每个班级超过50名学生。

此代码演示了如何在提交mview上使用快速刷新来强制执行学生计数限制

insert into class(class_id, class_name) values (1, 'Constraints 101');
insert into class(class_id, class_name) values (2, 'Constraints 201');
insert into student(student_id, student_name) values(1, 'Alice');
insert into student(student_id, student_name) values(2, 'Bob');
insert into student(student_id, student_name) values(3, 'Carlos');

create materialized view log on class_student_asc with primary key, rowid, sequence including new values;

create materialized view class_limit refresh fast on commit as
  select class_id, count(*) count from class_student_asc group by class_id;

alter table class_limit add constraint class_limit_max check(count <= 2);

insert into class_student_asc(class_id, student_id) values(1, 1);
insert into class_student_asc(class_id, student_id) values(1, 2);
insert into class_student_asc(class_id, student_id) values(1, 3);

提交交易时违反约束,而不是在第三个学生被添加到课程时。这可能会对您的应用程序代码产生影响。 SQL Developer无法显示错误,但sql * plus确实显示错误。

alt text http://i27.tinypic.com/5ajplw.png

答案 1 :(得分:0)

我可以想到几种方法:

<强> 1。触发器

在表上检查INSERT并为您进行验证。

<强> 2。一对一的关系

假设你想要一个父母只有两个孩子。创建两个一对一的关系。

答案 2 :(得分:0)

另一个问题有类似的要求,您可以使用CHECK约束和“count”列上的UNIQUE约束的组合来约束:

How to fastly select data from Oracle