2012-03-12 20 views
5

Estoy estudiando los factores desencadenantes y las limitaciones.SQL usando el disparador para la restricción

Y tengo una pregunta para usar gatillo (Para ser honesto, no estoy realmente seguro de cómo utilizar el gatillo ..)

Digamos que tenemos una mesa de maestros.

Y esta tabla maestra contiene teacher_id, SSN, nombre, apellido, class_time

por ejemplo,

|teacher_id|ssn | first_name | last_name | student_number| max_student 
|1   |1234 | bob  | Smith  | 25   |25 
|2   |1235 | kim  | Johnson | 24   |21 
|3   |1236 | kally  | Jones  | 23   |22 

y

digamos que el número máximo de número de estudiante será 25. (El número máximo de estudiantes será definido por el maestro, por lo que puede ser cualquier número como 10, 22, 25 ...)

y un estudiante quiere agregar el clas de bob s. Sin embargo, quiero hacer el disparador que rechaza agregar al estudiante. (Porque la clase de Bob ya está llena ...)

Sin embargo, no estoy seguro de cómo crear el disparador .. :(.. (this es la primera vez para estudiar sobre el gatillo ....)

puede ayudar a cualquier persona crear el código de ejemplo para entender parte gatillo?

+2

Tendrá que agregar la base de datos que le interese, ya que los desencadenantes tienden a ser específicos de la base de datos. –

+0

Bienvenido a StackOverflow: si publica código, XML o muestras de datos, ** por favor ** resalte esas líneas en el editor de texto y haga clic en el botón "muestras de código" ('{}') en la barra de herramientas del editor para formatear y sintaxis resaltarlo! No hay necesidad de ' ' orgías sucias y etiquetas '
', realmente .... –

+1

Esta es una regla de negocios, que esperaba que se implementara en el software de la aplicación en lugar de como un disparador o una restricción en la base de datos. Las restricciones y desencadenantes de la base de datos generalmente imponen la integridad referencial (es decir, mantienen la coherencia interna de los datos) y, aunque posiblemente sea un respaldo para garantizar que las clases no superen los 25, la aplicación realmente debería detener el intento en primer lugar. –

Respuesta

10

en primer lugar, creo que esto es una regla de datos y por lo tanto se debe hacer cumplir de forma centralizada. Es decir, debe haber una restricción de base de datos (o equivalente) impuesta por el DBMS que impida que todas las aplicaciones escriban datos incorrectos (en lugar de confiar en que los codificadores individuales de cada aplicación se abstengan de escribir datos incorrectos).

En segundo lugar, creo que es apropiado un activador AFTER (en lugar de un disparador INSTEAD OF).

En tercer lugar, esto se puede aplicar utilizando claves foráneas y restricciones de nivel de fila CHECK.

Para un desencadenador de tipo de restricción, la idea generalmente es escribir una consulta para devolver datos incorrectos, luego en la prueba de desencadenante, este resultado está vacío.

No ha publicado muchos detalles de sus tablas, así que lo adivinaré. Supongo que student_number está destinado a ser un conteo de estudiantes; ya que es suena como un identificador así que voy a cambiar el nombre y asumir el identificador para los estudiantes es 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; 

En SQL Server, la definición de un disparador sería algo como esto:

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; 

Sin embargo, hay algunas consideraciones adicionales. Ejecutar dicha consulta después de cada UPDATE en la tabla puede ser muy ineficiente. Debe usar UPDATE() (o COLUMNS_UPDATED si cree que se puede confiar en el orden de las columnas) y/o las tablas conceptuales deleted y inserted para limitar el alcance de la consulta y cuándo se activa. También deberá asegurarse de que las transacciones estén debidamente serializadas para evitar problemas de concurrencia. Aunque involucrado, no es terriblemente complejo.

Recomiendo encarecidamente el libro Applied Mathematics for Database Professionals  By Lex de Haan, Toon Koppelaars, capítulo 11 (los ejemplos del código son Oracle pero pueden ser fácilmente portados a SQL Server).


Es posible lograr lo mismo sin desencadenantes. La idea es hacer una superclave en (teacher_id, students_tally) a la que se hará referencia en la Inscripción, para la cual se mantendrá una secuencia de ocurrencias únicas de estudiantes con una prueba de que la secuencia nunca excederá la cuenta máxima.

He aquí algunos desnudos huesos DDL 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) 
); 

A continuación, añadir un poco de 'ayuda' almacenan procsos/funciona para mantener la secuencia en la actualización.

+0

lo siento, me olvidé de poner max_student de la tabla. Estoy estudiando para crear el GATILLO que puede verificar el límite de inscripción cuando el estudiante desea inscribir las clases. Por ejemplo, si max_student == student_number, el alumno no puede agregar la clase. De todos modos, realmente me ayuda a entender TRIGGER. Gracias :) –

Cuestiones relacionadas