Oracle - 如何根据属性记录对关系实施规则(简单示例)

发布于 2024-11-04 09:46:24 字数 333 浏览 1 评论 0原文

在学校系统中,我有两张表,一张称为“员工”,其中保存学校所有员工、教师、管理员、厨师和清洁工等的记录。然后我有第二张名为“课程”的表,其中包含与员工相关的外键以说明谁是课程领导者,现在我只想允许教师担任课程领导者,即厨师不能成为课程领导者,但我不确定如何在数据库级别上限制这一点。

注意:我在这里问了一个更复杂的错误问题 - Oracle 唯一约束 - 触发器检查新关系中的属性值

In a school system I have 2 tables, one called Staff which holds records of all member of staff for a school, teachers, admin, cooks and cleaners etc. Then I have a second table called Course with a foreign key relating to Staff to state who is the Course leader, now I only want to allow teachers to be the Course Leader, i.e. a cook can't be, but am not sure how to restrict this on the database level.

Note : I asked a more complicated wrong question here - Oracle Unique Constraint - Trigger to check value of property in new relation

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

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

发布评论

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

评论(5

别靠近我心 2024-11-11 09:46:24

您可以在curses tabelle 上的插入或更新后触发器中检查此限制。

CREATE or replace TRIGGER check_leader
AFTER INSERT OR UPDATE ON  Course
FOR EACH ROW
declare
  v_type varchar2(30);
BEGIN
  select type into v_type from stuff where :NEW.leader_id = stuff.stuff_id;
  if v_type != 'teacher' then 
   RAISE_APPLICATION_ERROR(-20000, 'course leader must be teacher');
  end if;
end;
/

但你需要在员工桌上另一个触发器。
如果东西类型发生变化(从教师到清洁工),则必须检查诅咒表中的条目。

CREATE or replace TRIGGER check_courses
AFTER UPDATE ON  STUFF
FOR EACH ROW
declare
  v_num number;
BEGIN
  if :OLD.type = 'teacher' and :NEW.type != 'teacher' then
     select count(*) into v_num from curses where courses.leader_id = :NEW.stuff_id;
     if v_num > 0 then 
       RAISE_APPLICATION_ERROR(-20000, 'there are courses assigned ');
      end if;
  end if;
end;
/

You could check this restriction within an after insert or update triger on curses tabelle.

CREATE or replace TRIGGER check_leader
AFTER INSERT OR UPDATE ON  Course
FOR EACH ROW
declare
  v_type varchar2(30);
BEGIN
  select type into v_type from stuff where :NEW.leader_id = stuff.stuff_id;
  if v_type != 'teacher' then 
   RAISE_APPLICATION_ERROR(-20000, 'course leader must be teacher');
  end if;
end;
/

But you need another trigger on the staff table.
In the case of a change of stuff type (from teacher to cleaner ) It must be checked for the entries in curses table.

CREATE or replace TRIGGER check_courses
AFTER UPDATE ON  STUFF
FOR EACH ROW
declare
  v_num number;
BEGIN
  if :OLD.type = 'teacher' and :NEW.type != 'teacher' then
     select count(*) into v_num from curses where courses.leader_id = :NEW.stuff_id;
     if v_num > 0 then 
       RAISE_APPLICATION_ERROR(-20000, 'there are courses assigned ');
      end if;
  end if;
end;
/
Saygoodbye 2024-11-11 09:46:24

在这种情况下,我会修改数据模型。我将采用通用表 Staff 并在其下添加每个 STAFF_TYPE 的表:CATERERS、TEACHERS、ADMIN 等。然后,在 COURSES 和 TEACHERS 之间强制使用外键就很简单了,无需触发器。

这是此类问题的标准解决方案。当您进一步调查这些要求时,您会发现厨师和清洁工也存在类似的外键问题。您也可能会发现教师具有而管理者所缺乏的某些属性。这就是为什么每种类型的单独表格很有用。同时,它们都有共同点。这就是为什么您需要一个 STAFF 超级类型的表。


当然,在提出这个答案时,我呼应@JeffreyKemp的 您上一个问题中的建议。好吧,正如 @RobVanWijk 借了我的,为什么不呢? :)

In this scenario I would revise the data model. I would take the generic table staff and add under it tables for each STAFF_TYPE: CATERERS, TEACHERS, ADMIN, etc. Then it is a simple matter to enforce a foreign key between COURSES and TEACHERS without the need for triggers.

This is a standard solution to this kind of problem. As you further investigate the requirements you'll find there will be similar foreign key issues with cooks and janitors. It is also likely that you will find there are attributes which teachers have that administrators lack. That's why separate tables for each type are useful. At the same time they all have things in common. That's why you need a table for the STAFF super type.


Of course, in proposing this answer I am echoing @JeffreyKemp's suggestion in your previous question. Well, as @RobVanWijk has borrowed mine, why not? :)

我的鱼塘能养鲲 2024-11-11 09:46:24

您可以添加另一个名为 COURSE_LEADERS 的表来跟踪当前能够主持课程的每个人,然后建立从 COURSECOURSE_LEADERS 的关系,如下所示以及从 COURSE_LEADERSTAFF 的关系。这样,厨师只能在 COURSE_LEADER 中主持一门课程,但如果这是一门关于烹饪的课程,也许可以……? ;)

当然,这种方法意味着必须有某种方法可以在 course_leader 中添加/删除工作人员。如果您希望它是自动的,则可以有一个触发器,当添加新的STAFF(如果员工是教师)时,该触发器会向COURSE_LEADER插入一条记录 - 假设这是可能的在插入记录时确定员工是否是教师。

You could add another table named COURSE_LEADERS to track everyone who is currently able to lead a course, then have a relation from COURSE to COURSE_LEADERS, as well as a relation from COURSE_LEADER to STAFF. This way, a cook can only lead a course if they are in COURSE_LEADER, but if it's a course aboue cooking, maybe that's OK...? ;)

This method of course, means that there must be some way to add/remove staff members from the course_leader. If you want it to be automatic, you could have a trigger that inserts a record to COURSE_LEADER when a new STAFF is added if the staff is a teacher - assuming that it's possible to determine if a staff is a teacher when their record is inserted.

天赋异禀 2024-11-11 09:46:24

你可以像APC在另一个线程中所说的那样做。

这是一个示例:

SQL> create table staff
  2  ( id         number(10)   not null primary key
  3  , name       varchar2(10) not null
  4  , staff_type varchar2(10) not null check (staff_type in ('TEACHER','COOK','ADMIN','CLEANER'))
  5  , constraint staff_uk unique (id,staff_type)
  6  )
  7  /

Table created.

SQL> insert into staff values (1, 'ALAN', 'COOK')
  2  /

1 row created.

SQL> insert into staff values (2, 'BOB', 'TEACHER')
  2  /

1 row created.

SQL> create table course
  2  ( id         number(10)   not null primary key
  3  , name       varchar2(30) not null
  4  , staff_id   number(10)   not null
  5  , staff_type varchar2(10) default 'TEACHER' not null
  6  , constraint course_staff_fk
  7      foreign key (staff_id,staff_type)
  8      references staff (id,staff_type)
  9  )
 10  /

Table created.

SQL> insert into course (id,name,staff_id) values (1, 'Mathematics', 1)
  2  /
insert into course (id,name,staff_id) values (1, 'Mathematics', 1)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCHEMA.COURSE_STAFF_FK) violated - parent key not found


SQL> insert into course (id,name,staff_id) values (2, 'Physics', 2)
  2  /

1 row created.

问候,
抢。

You can do it like APC said in the other thread.

Here is an example:

SQL> create table staff
  2  ( id         number(10)   not null primary key
  3  , name       varchar2(10) not null
  4  , staff_type varchar2(10) not null check (staff_type in ('TEACHER','COOK','ADMIN','CLEANER'))
  5  , constraint staff_uk unique (id,staff_type)
  6  )
  7  /

Table created.

SQL> insert into staff values (1, 'ALAN', 'COOK')
  2  /

1 row created.

SQL> insert into staff values (2, 'BOB', 'TEACHER')
  2  /

1 row created.

SQL> create table course
  2  ( id         number(10)   not null primary key
  3  , name       varchar2(30) not null
  4  , staff_id   number(10)   not null
  5  , staff_type varchar2(10) default 'TEACHER' not null
  6  , constraint course_staff_fk
  7      foreign key (staff_id,staff_type)
  8      references staff (id,staff_type)
  9  )
 10  /

Table created.

SQL> insert into course (id,name,staff_id) values (1, 'Mathematics', 1)
  2  /
insert into course (id,name,staff_id) values (1, 'Mathematics', 1)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCHEMA.COURSE_STAFF_FK) violated - parent key not found


SQL> insert into course (id,name,staff_id) values (2, 'Physics', 2)
  2  /

1 row created.

Regards,
Rob.

世界如花海般美丽 2024-11-11 09:46:24

我不认为在数据库级别执行此操作有什么意义,或者至少通过触发器等使您的生活变得复杂。

只需创建这些对象:

  • 一个名为 STAFF 的表,有一个“type”字段(类型可以为 NULL 或“COURSE LEADER”)
  • 一个名为 COURSE 的表,有一个指向 STAFF 的外键
  • 一个名为 COURSE_LEADERS 的视图,即 select * from STAFF where type="COURSE LEADER"

然后,在处理课程和课程领导时,在应用程序中仅使用 COURSE 和 COURSE_LEADERS 对象。就这么简单。

I don't see the point of doing this at database level, or, at least, complicate your life with triggers and so on.

Just create those objects:

  • a table named STAFF, that has a "type" field (type can be NULL or "COURSE LEADER")
  • a table named COURSE, that has a foreign key to STAFF
  • a view named COURSE_LEADERS, that is select * from STAFF where type="COURSE LEADER"

Then, use only COURSE and COURSE_LEADERS objects in your application when dealing with courses and course leaders. As simple as that.

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