Oracle SQL, Ищем идеи по ограничению - PullRequest
3 голосов
/ 17 октября 2011

У меня есть таблица со строками классов, учителей и лидеров,

Класс и Учитель - это числа, а Лидер - логическое значение (на самом деле это просто символ (1))

Таблица представляет отношения между учителями и классами.

В классе может быть много учителей, или в классе много учителей.

Мне нужно сделать ограничение или проверку, чтобы для каждого отдельного класса, одной и только одной из строк, в которых он встречается, Leader имел значение true.

Например.

Teacher |  Class | Leader
   1    |    1   |  True
   2    |    1   |  False
   2    |    2   |  True

Будет принято, поскольку каждый отдельный класс имеет одну строку, в которой он встречается, со значением Leader, равным true, но не более одной строки.

Буду признателен, если кто-нибудь сможет предложить идею о том, как представить это как ограничение.

Ответы [ 5 ]

8 голосов
/ 17 октября 2011

Достаточно просто создать индекс на основе функций, который обеспечивает выполнение части «не более одного лидера» ограничения

CREATE UNIQUE INDEX one_leader_per_class
    ON your_table_name( (CASE WHEN leader = 'Y' 
                              THEN class
                              ELSE null
                          END) );

К сожалению, создать декларативное ограничение, которое обеспечивает выполнение, не так просто.Требование, чтобы у каждого класса был лидер.Единственный декларативный способ сделать это - создать материализованное представление, объединяющее данные по классам, установить для этого материализованного представления значение REFRESH FAST и создать ограничение на материализованное представление, обеспечивающее столбец NUM_LEADERS.в материализованном представлении всегда 1. Это требует, чтобы вы создали соответствующий материализованный журнал представления, который добавляет накладные расходы к DML на таблице.Это также означает, что ограничение не будет нарушено до тех пор, пока вы не совершите фиксацию, что может быть проблематично, если ваши приложения не написаны так, чтобы предполагать, что фиксация может когда-либо закончиться неудачей.

1 голос
/ 17 октября 2011

Другим способом было бы создать таблицу под названием Leader с:

CREATE TABLE Leader
( Class
, Teacher
, PRIMARY KEY (Class)
, FOREIGN KEY (Class, Teacher)
    REFERENCES ClassTeacher (Class, Teacher)
) ;

и удалите столбец ClassTeacher.Leader.

1 голос
/ 17 октября 2011

Рассмотрите возможность изменения столбца is_Leader (логический) на leadership_rank (целое число), создайте составное уникальное ограничение для (Teacher, Class leadership_rank).Затем немного измените семантику, чтобы каждый учитель получил уникальное случайное / возрастающее / значащее целочисленное значение.Тогда объявленным лидером класса является учитель, где leadership_rank = 1 (или, возможно, самый низкий ранг для группы, чтобы сделать вещи немного более гибкими), возможно, с использованием представления.

1 голос
/ 17 октября 2011

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

Поскольку между классом и лидером существуют отношения один-к-одному Самый простой способ добиться желаемых результатов, который я вижу, - сохранить лидера (class_teacher_id) с записью класса. Вам нужно будет добавить уникальный суррогатный ключ (class_teacher_id) в таблицу «многие ко многим» (class_teacher), после чего вы можете удалить логический столбец лидера.

Если возможно иметь класс без лидера, просто позвольте ученику быть обнуляемым и, конечно, не забудьте создать ограничения внешнего ключа, чтобы обеспечить ссылочную целостность между class.leaderid и новым class_teacher.class_teacher_id.

0 голосов
/ 17 октября 2011

Для выполнения требования, чтобы у каждого класса был лидер, вы можете использовать Триггер

CREATE OR REPLACE TRIGGER tc
AFTER INSERT OR UPDATE OR DELETE
ON table_name
DECLARE
 v_res NUMBER;
BEGIN
  select count(*) 
  into v_res 
  from (
        select class from table_name
        minus
        select class from table_name where leader = 'Y'
        )
  ;

   if v_res > 0 
   then 
    raise_application_error(-20000, 'each class must have a leader'); 
   end if; 
END;
/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...