2012-03-12 8 views
5

トリガと制約を調べています。トリガを使用してSQLに制約を設定する

そして、私は疑問トリガーを使用するようになった(私はトリガを使用するかどうかは本当にわからない、正直に言うと...)

のは、私たちは教師のテーブルがあるとしましょう。

そして、この教師の表はteacher_id、SSN、FIRST_NAME、LAST_NAME、例えば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 ...などの任意の数字にすることができます)

生徒はボブのクラスを追加したいs。しかし、私は生徒を追加することを拒否するトリガーを作っています(ボブのクラスはすでに満員ですから)

しかし、私は本当にトリガーを作成する方法はわかりません。

は誰の助けがトリガー部分を理解するためのサンプルコードを作成することができますか?

+2

トリガーはデータベース固有の傾向があるため、興味のあるデータベースを追加する必要があります。 –

+0

ようこそStackOverflow:コード、XML、またはデータサンプルを投稿する場合は、テキストエディタでこれらの行を強調表示し、エディタツールバーの "コードサンプル"ボタン( '{}')をクリックしてください。それを強調する構文!   'orgiesと'
'タグは本当に必要ありません。 –

+1

これはビジネスルールです。これは、データベースのトリガーや制約としてではなく、アプリケーションソフトウェアで実装すると予想されます。データベースの制約とトリガーは、一般に参照整合性を強制します(つまり、内部的にデータの一貫性を維持します)。クラスが25を超えないようにするためのバックストップになるかもしれませんが、アプリはまず最初にその試みを止めるべきです。 –

答えて

10

まず、私は、これはデータ・ルールであるため、一元的に実施されるべきだと思う)....トリガーについて勉強するのは初めてです。つまり、すべてのアプリケーションが不正なデータを書き込むのを防ぐDBMSによって(各アプリケーションの個々のコーダに悪いデータを書き込まないようにする)DBの制約が適用されます。

第2に、AFTERトリガーが適切だと思う(INSTEAD OFトリガーではなく)。

第3に、これは外部キーと行レベルCHECKの制約を使用して強制できます。

制約タイプのトリガーでは、一般に、トリガーテストでは、この結果が空であることを示すために、不良データを返すクエリを記述します。

私は推測するように、テーブルの詳細を多く投稿していません。私はstudent_numberと書いてあります。それは私が名前を変更し、学生のための識別子を仮定しますので、それは識別子のような音であるとしてstudent_id次のとおりです。

SQL Serverでの
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; 

、トリガ定義は、次のようになります

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の概念表を使用して、クエリの範囲と発生する時間を制限する必要があります。並行性の問題を防ぐために、トランザクションが適切にシリアル化されていることを確認する必要もあります。関与していますが、それはひどく複雑ではありません。

Applied Mathematics for Database Professionals  By Lex de Haan, Toon Koppelaarsの第11章(コード例はOracleですが、SQL Serverに簡単に移植することができます)を強くお勧めします。


トリガーなしで同じことを達成することは可能かもしれません。この考えは(teacher_id, students_tally)のスーパーキーをEnrollmentで参照させることです。そのために、シーケンスが最大の集計を決して超えないというテストでユニークな生徒の出現が維持されます。

ここではいくつかの裸の骨の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) 
); 

その後の更新にシーケンスを維持するために、いくつかの「ヘルプ」保存されprocsの/機能を追加します。

+0

申し訳ありませんが、私はテーブルからmax_studentを置くことを忘れてしまいます。学生がクラスを登録したいときに、登録の制限をチェックできるTRIGGERを作成するために勉強しています。たとえば、max_student == student_numberの場合、学生はクラスを追加できません。とにかく、本当にTRIGGERを理解するのに役立ちます。ありがとう:) –

関連する問題