3

学生は月額を支払う学校に通っています。その値は(FatherSalary + MotherSalary)*0.05

昨日トリガーの勉強を始めたばかりです。トリガーを作成しましたが、エラーが発生しました。

メッセージ515、レベル16、状態2、プロシージャTR_Calc_Value、25行
目列'IDStudent'、テーブル'HW32.dbo.Enrollment'に値NULLを挿入できません。列はnullを許可しません。INSERTは失敗します。

テーブルに値を挿入するとEnrollment。これを解決する方法はありますか?

USE master;

IF DB_ID (N'HW32') IS NOT NULL
   DROP DATABASE HW32;

CREATE DATABASE HW32;

USE HW32
CREATE TABLE Family(
  IDFamily int IDENTITY(1,1),
  FirstName nchar(20) NOT NULL,
  LastName nchar(20) NOT NULL,
  Gender nchar(1)  NOT NULL,
  Salary money,
  CONSTRAINT PK_Family PRIMARY KEY(IDFamily),
  CONSTRAINT CK_Family_Gender CHECK (Gender IN ('M','F'))
) 

CREATE TABLE Student(
  IDStudent int IDENTITY(1,1),
  FirstName nchar(20) NOT NULL,
  LastName nchar(20) NOT NULL,
  CONSTRAINT PK_Student PRIMARY KEY(IDStudent)
)

CREATE TABLE Filiation(
  IDStudent int,
  IDFamily int,
  Filiation nchar(20) NOT NULL,
  CONSTRAINT FK_Filiation_IDStudent FOREIGN KEY (IDStudent)
  REFERENCES Student(IDStudent),
  CONSTRAINT FK_Filiation_IDFamily FOREIGN KEY (IDFamily)
  REFERENCES Family(IDFamily),
  CONSTRAINT PK_Filiation PRIMARY KEY(IDStudent,IDFamily)
)

CREATE TABLE Enrollment(
  IDEnrollment int IDENTITY(1,1),
  IDStudent int NOT NULL,
  Status nchar(20) NOT NULL,
  MonthlyPayment money,
  CONSTRAINT PK_Enrollment PRIMARY KEY(IDStudent), 
  CONSTRAINT FK_Enrollment_IDStudent FOREIGN KEY (IDStudent)
  REFERENCES Student(IDStudent),
  CONSTRAINT CK_Enrollment_Status CHECK(Status IN('Acepted','Rejected')),
  CONSTRAINT UC_Enrollment UNIQUE (IDEnrollment)
)

USE HW32
GO
CREATE TRIGGER TR_Calc_Value 
ON Enrollment 
AFTER INSERT, UPDATE AS
    DECLARE @monthlyPayment money, @sFather money, @sMother money
BEGIN
    SET @sFather = (SELECT FAM.Salary
            FROM Family FAM 
            LEFT JOIN Filiation F ON F.IDFamily = FAM.IDFamily
            LEFT JOIN inserted I ON I.IDStudent = F.IDStudent
            WHERE F.IDStudent = I.IDStudent AND FAM.Gender = 'M')

    SET @sMother = (SELECT FAM.Salary 
            FROM Family FAM 
            LEFT JOIN Filiation F ON F.IDFamily = FAM.IDFamily
            LEFT JOIN inserted I ON I.IDStudent = F.IDStudent
            WHERE F.IDStudent = I.IDStudent AND FAM.Gender = 'F')

    SET @monthlyPayment = ((@sFather + @sMother) * 0.05)

    INSERT INTO Enrollment (MonthlyPayment) VALUES (@monthlyPayment)
END
GO

USE HW32
INSERT INTO Family VALUES('John', 'Smith', 'M', 800)
INSERT INTO Family VALUES('Anna', 'Smith', 'F', 800)

INSERT INTO Student VALUES('Carl', 'Smith')

INSERT INTO Filiation VALUES(1, 1, 'Father')
INSERT INTO Filiation VALUES(1, 2, 'Mother')

INSERT INTO Enrollment (IDStudent, Status) VALUES(1, 'Accepted')
4

1 に答える 1

6

トリガーに行を挿入する必要はありません。行はすでに追加されています。代わりに、 UPDATEを実行します。

CREATE TRIGGER TR_Calc_Value ON Enrollment AFTER INSERT, UPDATE AS
BEGIN
   UPDATE E 
   set MonthlyPayment = (

      select 0.05 * SUM(Salary) 
      from Family FAM 
      inner join Filiation F 
      on FAM.IDFamily= F.IDFamily 
      where F.IDStudent = I.IDStudent
      )

   from Enrollment E
   inner join inserted I
   on E.IDEnrollment=  I.IDEnrollment

注意事項

  • inserted上記は、複数の行を含むことに適切に対処します
  • 私は父と母を区別しません(彼らは同じように扱われているように見えるので)
  • 生徒に関連付けられている父親と母親が複数いる場合は、それらすべてが含まれます。これが正しいかどうかは議論の余地があり、より良い制約では不可能かもしれませんが、元のトリガーもこの状況にまったく対処していません。

私のコメントによると、他のテーブルから常に再計算できる場合は、この情報を保存しないことをお勧めします(この場合、それが正しいかどうかはわかりませんが、他のテーブルを反映する必要がある場合は、さらに多くのトリガーが必要になりますすべての一貫性を保つため。

また、per-marcの削除された回答として、挿入を行うときに常に列リストを指定することも良い習慣になります。これはこの特定のエラーの原因ではありませんが、意図をより適切に文書化するのに役立ち、目視検査によって発生する可能性のあるエラーをすばやく排除するのに役立ちます。

于 2012-12-02T12:26:41.343 に答える