Во-первых, я думаю, что это правило данных и поэтому должно применяться централизованно.То есть должно быть ограничение базы данных (или его эквивалент), применяемое СУБД, которое не позволяет всем приложениям записывать неверные данные (вместо того, чтобы полагаться на то, что отдельные кодировщики каждого приложения воздерживаются от записи неверных данных).
Во-вторых, я думаю, что уместен триггер AFTER
(а не триггер INSTEAD OF
).
В-третьих, это может быть выполнено с использованием ограничений внешнего ключа и CHECK
на уровне строк.
Для триггера типа ограничения идея обычно состоит в том, чтобы написать запрос для возврата неверных данных, а затем в тесте триггера, чтобы этот результат был пустым.
Вы не опубликовали много подробностей о своих таблицах, поэтому я будуУгадай.Я предполагаю, что student_number
предназначен для подсчета студентов;поскольку он звучит как идентификатор, поэтому я изменю имя и предположу, что идентификатор для студентов равен student_id
:
WITH EnrolmentTallies
AS
(
SELECT teacher_id, COUNT(*) AS students_tally
FROM Enrolment
GROUP
BY teacher_id
)
SELECT *
FROM Teachers AS T
INNER JOIN EnrolmentTallies AS E
ON T.teacher_id = E.teacher_id
AND E.students_tally > T.students_tally;
В SQL Server определение триггера будет выглядеть примерно так:
CREATE TRIGGER student_tally_too_high ON Enrolment
AFTER INSERT, UPDATE
AS
IF EXISTS (
SELECT *
FROM Teachers AS T
INNER JOIN (
SELECT teacher_id, COUNT(*) AS students_tally
FROM Enrolment
GROUP
BY teacher_id
) AS E
ON T.teacher_id = E.teacher_id
AND E.students_tally > T.students_tally
)
BEGIN
RAISERROR ('A teachers''s student tally is too high to accept new students.', 16, 1);
ROLLBACK TRANSACTION;
RETURN
END;
Однако существуют и другие соображения.Выполнение такого запроса после каждого UPDATE
к таблице может быть очень неэффективным.Вам следует использовать UPDATE()
(или COLUMNS_UPDATED
, если вы считаете, что можно упорядочить столбцы) и / или концептуальные таблицы deleted
и inserted
, чтобы ограничить объем запроса и его запуск.Вам также необходимо убедиться, что транзакции правильно сериализованы для предотвращения проблем параллелизма.Несмотря на это, это не очень сложно.
Я настоятельно рекомендую книгу Прикладная математика для специалистов по базам данных. Лекс де Хаан, Тун Коппелаарс , глава 11 (примеры кода - Oracle, но можетможет быть легко перенесен на SQL Server).
Возможно добиться того же без триггеров.Идея состоит в том, чтобы создать суперключ на (teacher_id, students_tally)
для ссылки в Enrollment, для которого будет поддерживаться последовательность уникальных вхождений учащихся с проверкой, что последовательность никогда не превысит максимальное число.
Вот некоторыеBDN SQL DDL:
CREATE TABLE Students
(
student_id INTEGER NOT NULL,
UNIQUE (student_id)
);
CREATE TABLE Teachers
(
teacher_id INTEGER NOT NULL,
students_tally INTEGER NOT NULL CHECK (students_tally > 0),
UNIQUE (teacher_id),
UNIQUE (teacher_id, students_tally)
);
CREATE TABLE Enrolment
(
teacher_id INTEGER NOT NULL UNIQUE,
students_tally INTEGER NOT NULL CHECK (students_tally > 0),
FOREIGN KEY (teacher_id, students_tally)
REFERENCES Teachers (teacher_id, students_tally)
ON DELETE CASCADE
ON UPDATE CASCADE,
student_id INTEGER NOT NULL UNIQUE
REFERENCES Students (student_id),
student_teacher_sequence INTEGER NOT NULL
CHECK (student_teacher_sequence BETWEEN 1 AND students_tally)
UNIQUE (teacher_id, student_id),
UNIQUE (teacher_id, student_id, student_teacher_sequence)
);
Затем добавьте некоторые сохраненные «справочные» процессы / функции, чтобы сохранить последовательность при обновлении.