Oracle(或任何关系型)数据模型问题。父母有固定数量的孩子吗?

发布于 2024-09-11 10:18:52 字数 2492 浏览 7 评论 0原文

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

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

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) 上的触发器来实现它。

在插入前、更新触发器中查询同一个表以获取计数。 由于这会产生变异表错误,因此将其分为两个不同的语句级别 触发器(语句前和语句后)来实现结果。

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

b)

在类表中包含一个计数变量,并在将记录插入子表之前锁定父记录以进行更新。

所以,类似......

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

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

请指教。

This is a particular problem that I have come across many times,
but I have never really found a simple solution to this (seemingly) simple problem.

How to you ensure that a given parent has a fixed number of children?

1) Example.

How do you make sure a given class has only , say, 50 students enrolled..?

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

These are the implementations that I know of.
Let me know which one you'd prefer and if there is a simpler way to achieve this.

a)

Implementing it with triggers on the child table (class_student_asc).

Querying the same table in a before insert, update trigger to get the count.
Since this gives the mutating table error, this is split into two different statement-level
triggers (before-statement and after-statement) to achieve the result..

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

b)

Include a count variable in the class table and lock the parent record for update before inserting a record ito the child table.

So, something like..

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

and instead of exposing the table class_student_asc for inserts and so on...
write a procedure and then use it in all applications..

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)

There are, of course, cases like a user having two email adresses.
In such a scenario, the email address itself does not have any attribute
and the table could be as simple as

create table user_table
          (
            user_id number,
            user_name varchar2(50),
            user_email_primary varchar2(50),
            user_email_secondary varchar2(50)
          );

However, we cannot extend the same approach for the question above.....as the number of columns and the constraint checks would slow down the inserts and updates . Also, this would mean we'd need a new column added everytime we change the rule.. too.

Please advice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

两个我 2024-09-18 10:18:52

对于 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 会显示该错误。

替代文本

For Oracle consider this approach.

Create a materialized view summarising the number of students per class. Have the mview refresh on commit and add a constraint to the mview that prohibits a count of more than 50 students per class.

This code demonstrates how to use a fast refresh on commit mview to enforce the student count limit,

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

The constraint will be violated when the transaction is committed, not when the third student is added to the class. This might make a difference to your application code. SQL Developer fails to display the error but sql*plus does display it.

alt text

你的他你的她 2024-09-18 10:18:52

我可以想到几种方法:

1。触发器

在表上有一个 INSERT 触发器,用于检查 INSERT 并为您进行验证。

2.一对一关系

假设您希望一位父母只拥有两个孩子。创建两个一对一的关系。

I can think of a couple of ways:

1. Triggers

Have an INSERT Trigger on the table that checks on INSERT and does the validation for you.

2. One-to-One relationships

Let's say you want one parent to have only two children. Create two one-to-one relationships.

空袭的梦i 2024-09-18 10:18:52

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

如何快速从Oracle中选择数据

Another question had a similar requirement, which you can constrain using a combination of a CHECK constraint with a UNIQUE constraint on a "count" column:

How to fastly select data from Oracle

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文