在插入数据行时创建触发器并检查具有给定范围内值的特定列
Create a trigger when Inserting Data Row and check specific Column that have values in given range
触发器不工作。我只想不允许输入不在数据库范围内的标记。
这是我试过的代码。
table
CREATE Table Marks
(
TestID VARCHAR(10),
StudentID VARCHAR(10),
Grade CHAR(1),
Marks FLOAT,
IssuedDate VARCHAR(10),
PRIMARY KEY (TestID, StudentID),
CONSTRAINT FK66
FOREIGN KEY(TestID) REFERENCES Test(TestID),
CONSTRAINT FK77
FOREIGN KEY(StudentID) REFERENCES Student(StudentID)
)
触发器:
CREATE TRIGGER checkRange
ON Marks
FOR INSERT
AS
BEGIN
DECLARE @marks FLOAT
DECLARE @tID VARCHAR(10)
DECLARE @stID VARCHAR(10)
SELECT @marks = Marks, @tID = TestID, @stID = StudentID
FROM inserted
IF (((@marks) < 0) AND ((@marks) > 100))
ROLLBACK TRANSACTION
DELETE FROM Marks
WHERE TestID = @tID AND StudentID = @stID
END
正在插入数据:
INSERT INTO Marks
VALUES ('T02','ST00000001','F',110,'2019-08-24')
IF((@marks > 100.00) OR (@marks < 0.00))
到目前为止,更好的答案是 check constraint
。但我会把我的留在这里,以便您更好地理解触发器。
您实际要寻找的是类似以下内容的内容,它处理 Inserted
可以有 0-N 行的事实(当 Inserted
包含除 1 以外的任何内容时,您当前的解决方案将中断行)。
鉴于您已经发出了 ROLLBACK
,可能没有理由 DELETE
任何东西,除非您想删除在当前 INSERT
语句之前添加的行。
CREATE TRIGGER checkRange
ON Marks
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM Inserted I
WHERE Marks > 100.00 OR Marks < 0.00
) BEGIN
--ROLLBACK TRANSACTION;
-- Don't rollback in a trigger, throw instead. "A rollback causes a weird error The transaction ended in the trigger. The batch has been aborted" (thanks Charlieface).
THROW 51000, 'Marks are out of range, either > 100 or < 0.', 1;
END;
END;
我认为的注释:
varchar(10)
是PK的糟糕选择,为什么不用int identity
?
float
对 Marks 来说是一个糟糕的选择,除非你正在存储科学信息,否则你不应该使用 float
因为它不存储精确的数字。你想要一个 decimal(9,2)
或类似的东西。
varchar(10)
是一个糟糕的日期选择,请使用 date
日期类型,否则您将在余生中遇到此问题。
正如其他人所提到的,您的触发器存在一些严重问题。
看来您需要 Marks
列在每个学生的每个测试中在 0-100 之间,如果这样,更好的解决方案是检查约束:
ALTER TABLE Marks
ADD CONSTRAINT CHK_Marks
CHECK (Marks >= 0 AND Marks <= 100);
触发器不工作。我只想不允许输入不在数据库范围内的标记。
这是我试过的代码。
table
CREATE Table Marks
(
TestID VARCHAR(10),
StudentID VARCHAR(10),
Grade CHAR(1),
Marks FLOAT,
IssuedDate VARCHAR(10),
PRIMARY KEY (TestID, StudentID),
CONSTRAINT FK66
FOREIGN KEY(TestID) REFERENCES Test(TestID),
CONSTRAINT FK77
FOREIGN KEY(StudentID) REFERENCES Student(StudentID)
)
触发器:
CREATE TRIGGER checkRange
ON Marks
FOR INSERT
AS
BEGIN
DECLARE @marks FLOAT
DECLARE @tID VARCHAR(10)
DECLARE @stID VARCHAR(10)
SELECT @marks = Marks, @tID = TestID, @stID = StudentID
FROM inserted
IF (((@marks) < 0) AND ((@marks) > 100))
ROLLBACK TRANSACTION
DELETE FROM Marks
WHERE TestID = @tID AND StudentID = @stID
END
正在插入数据:
INSERT INTO Marks
VALUES ('T02','ST00000001','F',110,'2019-08-24')
IF((@marks > 100.00) OR (@marks < 0.00))
到目前为止,更好的答案是 check constraint
。但我会把我的留在这里,以便您更好地理解触发器。
您实际要寻找的是类似以下内容的内容,它处理 Inserted
可以有 0-N 行的事实(当 Inserted
包含除 1 以外的任何内容时,您当前的解决方案将中断行)。
鉴于您已经发出了 ROLLBACK
,可能没有理由 DELETE
任何东西,除非您想删除在当前 INSERT
语句之前添加的行。
CREATE TRIGGER checkRange
ON Marks
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (
SELECT 1
FROM Inserted I
WHERE Marks > 100.00 OR Marks < 0.00
) BEGIN
--ROLLBACK TRANSACTION;
-- Don't rollback in a trigger, throw instead. "A rollback causes a weird error The transaction ended in the trigger. The batch has been aborted" (thanks Charlieface).
THROW 51000, 'Marks are out of range, either > 100 or < 0.', 1;
END;
END;
我认为的注释:
varchar(10)
是PK的糟糕选择,为什么不用int identity
?float
对 Marks 来说是一个糟糕的选择,除非你正在存储科学信息,否则你不应该使用float
因为它不存储精确的数字。你想要一个decimal(9,2)
或类似的东西。varchar(10)
是一个糟糕的日期选择,请使用date
日期类型,否则您将在余生中遇到此问题。
正如其他人所提到的,您的触发器存在一些严重问题。
看来您需要 Marks
列在每个学生的每个测试中在 0-100 之间,如果这样,更好的解决方案是检查约束:
ALTER TABLE Marks
ADD CONSTRAINT CHK_Marks
CHECK (Marks >= 0 AND Marks <= 100);