2012-03-12 135 views
5

我正在學習觸發器和約束。SQL使用觸發器進行約束

而且我有一個問題想使用觸發器(說實話,我真的不知道如何使用觸發器..)

比方說,我們有一個教師表。

而這個老師表包含teacher_id,SSN,名字,姓氏,class_time

例如,

|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 

讓我們說的學生數量最大數量將是25(學生的最大數目由老師來定義,所以它可以是任何數字,如10,22,25 ...)

和學生要添加的bob的CLAS秒。不過,我想作出這樣的拒絕添加的學生動了扳機。(因爲Bob的類是已經滿了..)

但是,我真的不知道要創建觸發器的方式.. :(..(這是第一次來研究有關觸發....)

誰能幫助創建示例代碼,瞭解觸發部分?

+2

您必須添加您感興趣的數據庫,因爲觸發器往往是數據庫特定的。 – 2012-03-12 07:40:36

+0

歡迎使用StackOverflow:如果您發佈代碼,XML或數據樣本,請**在文本編輯器中突出顯示這些行,然後單擊編輯器工具欄上的「代碼示例」按鈕(「{}」)以精確地格式化和語法突出它!不需要雜亂的' 'orgies和'
'標籤,真的...... – 2012-03-12 07:46:07

+1

這是一個業務規則,我希望這可以在您的應用程序軟件中實現,而不是作爲數據庫中的觸發器或約束。數據庫約束和觸發器通常強制引用完整性(也就是說,它們保持內部數據一致),雖然它可能是確保類不超過25的支持者,但應用程序應該真正停止嘗試。 – 2012-03-12 08:12:42

回答

10

首先,我認爲這是一個數據規則,因此應該集中執行。也就是說,應該有一個由DBMS強制執行的數據庫約束(或等效),以防止所有應用程序寫入錯誤的數據(而不是依靠每個應用程序的單個編碼器來避免寫入錯誤的數據)

其次,我認爲一個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(如果您認爲可以依賴列排序)和/或deletedinserted概念表來限制查詢的範圍以及何時觸發。您還需要確保事務正確序列化以防止出現併發問題。雖然涉及,但並不複雜。

我強烈推薦這本書Applied Mathematics for Database Professionals  By Lex de Haan, Toon Koppelaars,第11章(代碼示例是甲骨文,但可以很容易地移植到SQL Server)。


不用觸發器就可以達到同樣的效果。這個想法是在登記中引用(teacher_id, students_tally)的超級密鑰,對於這個唯一的學生事件序列將通過測試保持序列永遠不會超過最大計數。

下面是一些裸露的骨頭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) 
); 

然後添加存儲的特效/功能上保持更新序列一些「幫助」。

+0

對不起,我忘了把max_student放在桌子上。我正在學習創建能夠在學生想要參加課程時檢查報名限額的TRIGGER。例如,如果max_student == student_number則學生不能添加該類。無論如何,它真的幫助我理解TRIGGER。謝謝 :) – 2012-03-12 09:18:00