In primo luogo, credo che questa è una regola di dati e quindi dovrebbe essere applicata a livello centrale. Cioè, dovrebbe esserci un vincolo di database (o equivalente) applicato dal DBMS che impedisce a tutte le applicazioni di scrivere dati non validi (piuttosto che affidarsi ai singoli codificatori di ciascuna applicazione per astenersi dal scrivere dati errati).
In secondo luogo, penso che un trigger AFTER
sia appropriato (piuttosto che un trigger INSTEAD OF
).
In terzo luogo, questo può essere applicato utilizzando la chiave esterna e i vincoli CHECK
a livello di riga.
Per un trigger del tipo di vincolo, l'idea generalmente è di scrivere una query per restituire dati non validi, quindi nel test di attivazione questo risultato è vuoto.
Non hai pubblicato molti dettagli dei tuoi tavoli, quindi suppongo. Presumo che lo student_number
sia destinato a essere un numero di studenti; come è che suona come un identificatore così cambierò il nome e assumere l'identificatore per gli studenti è 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;
In SQL Server, la definizione grilletto sarebbe simile a questa:
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;
Ci sono alcune ulteriori considerazioni, tuttavia. L'esecuzione di una query di questo tipo dopo ogni UPDATE
nella tabella potrebbe essere molto inefficiente. È necessario utilizzare UPDATE()
(o COLUMNS_UPDATED
se si ritiene che l'ordine delle colonne possa essere invocato) e/o le tabelle concettuali deleted
e inserted
per limitare l'ambito della query e quando è attiva. Sarà inoltre necessario assicurarsi che le transazioni siano serializzate correttamente per evitare problemi di concorrenza. Sebbene coinvolto, non è terribilmente complesso.
Consiglio vivamente il libro Applied Mathematics for Database Professionals By Lex de Haan, Toon Koppelaars, capitolo 11 (gli esempi di codice sono Oracle ma possono essere facilmente portati su SQL Server).
Potrebbe essere possibile ottenere lo stesso senza trigger. L'idea è di creare un superkey su (teacher_id, students_tally)
a cui fare riferimento nell'iscrizione, per il quale verrà mantenuta una sequenza di occorrenze di studenti unici con un test che la sequenza non supererà mai il conteggio massimo.
Ecco alcuni nudo DDL ossa SQL:
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)
);
poi aggiungere un po 'di aiuto' memorizzati procs/funzioni per mantenere la sequenza aggiornata.
Dovrai aggiungere il database a cui sei interessato, poiché i trigger tendono ad essere specifici del database. –
Benvenuti in StackOverflow: se inserisci codice, XML o campioni di dati, ** per favore ** evidenzia queste righe nell'editor di testo e fai clic sul pulsante "esempi di codice" ('{}') sulla barra degli strumenti dell'editor per formattarlo e la sintassi lo evidenzia! Non c'è bisogno di 'orge' 'tag e'
', in realtà .... –
Questa è una regola aziendale, che avrei dovuto essere implementata nel software applicativo piuttosto che come trigger o vincolo nel database. I vincoli ei trigger del database generalmente applicano l'integrità referenziale (ovvero mantengono i dati coerenti internamente) e sebbene possa essere un backstop per garantire che le classi non superino i 25, la tua app dovrebbe davvero interrompere il tentativo in primo luogo. –