оракул (или любой реляционный) вопрос модели данных. Родитель с фиксированным количеством детей? - PullRequest
5 голосов
/ 28 июля 2010

Это особая проблема, с которой я сталкивался много раз, но я так и не нашел простого решения этой (казалось бы) простой проблемы.

Как обеспечить, чтобы у данного родителя было фиксированное количество детей?

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

Это те реализации, о которых я знаю. Дайте мне знать, какой из них вы бы предпочли, и если есть более простой способ добиться этого.

а)

Реализация с помощью триггеров на дочерней таблице (class_student_asc).

Запрос к той же таблице в перед вставкой, триггер обновления, чтобы получить количество. Так как это приводит к ошибке таблицы мутаций, это делится на два разных уровня оператора триггеры (оператор до и после) для достижения результата.

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

б) * * тысяча двадцать-одна Включите переменную 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; в)

Есть, конечно, случаи, когда у пользователя есть два адреса электронной почты. В таком случае сам адрес электронной почты не имеет никакого атрибута и таблица может быть такой простой, как

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

Однако мы не можем расширить тот же подход для вопроса, приведенного выше ....., поскольку количество столбцов и проверка ограничений будут замедлять вставки и обновления. Кроме того, это будет означать, что нам нужно будет добавлять новый столбец каждый раз, когда мы меняем правило ... тоже.

Пожалуйста, совет.

Ответы [ 3 ]

5 голосов
/ 28 июля 2010

Для 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

0 голосов
/ 29 июля 2010

Другой вопрос имел аналогичное требование, которое можно ограничить, используя комбинацию ограничения CHECK с ограничением UNIQUE для столбца «count»:

Как быстро выбирать данные из Oracle

0 голосов
/ 28 июля 2010

Я могу придумать несколько способов:

1.Триггеры

Наличие на столе триггера INSERT, который проверяет INSERT и выполняет проверку для вас.

2.Отношения один-к-одному

Допустим, вы хотите, чтобы у одного родителя было только два ребенка.Создайте два отношения один-к-одному.

...