Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 插入数据行时创建触发器,并检查具有给定范围值的特定列_Sql_Sql Server_Tsql_Triggers - Fatal编程技术网

Sql 插入数据行时创建触发器,并检查具有给定范围值的特定列

Sql 插入数据行时创建触发器,并检查具有给定范围值的特定列,sql,sql-server,tsql,triggers,Sql,Sql Server,Tsql,Triggers,触发器不工作。我只想不允许输入不在数据库范围内的标记 这是我试过的代码 桌子 CREATE Table Marks ( TestID VARCHAR(10), StudentID VARCHAR(10), Grade CHAR(1), Marks FLOAT, IssuedDate VARCHAR(10), PRIMARY KEY (TestID, StudentID), CONSTRAINT FK66 FOREIGN

触发器不工作。我只想不允许输入不在数据库范围内的标记

这是我试过的代码

桌子

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

到目前为止,更好的答案是检查约束。但我会把我的留在这里,让你更好地理解

您实际要查找的是以下内容,它处理插入的行可以有0-N行的事实,当插入的行包含除1行以外的任何行时,当前解决方案将中断

如果已经发出回滚,则可能没有理由删除任何内容,除非要删除在当前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;
注意,我认为:

varchar10对于PK来说是个糟糕的选择,为什么不使用int标识呢? 对于标记来说,浮点是一个糟糕的选择,除非您存储的是科学信息,否则永远不要使用浮点,因为它不能存储精确的数字。你需要一个小数点9,2或类似的数字。 varchar10对于约会来说是一个糟糕的选择,请使用日期类型,否则您将在它的余生中遇到问题。
正如其他人提到的,你的触发器有很多严重的问题

似乎您需要每个学生每次测试的分数列在0-100之间,如果是这样,更好的解决方案是检查约束:

更改表格标记 添加约束CHK_标记
复选标记>=0,并且您正在使触发器101出错,插入的标记可以有0-N行,而不仅仅是1行。您必须像对待任何表一样对待它,并使用基于集合的操作,而不是过程逻辑。这部剧怎么演。触发器不起作用实际上意味着什么?我刚刚在这里发现了问题IF@marks100'当我更改时触发器正在工作'IF@marks>100.00'我想检查标记是否为0或大于100。但是如果插入两行,则不起作用。为什么在此处使用触发器?约束似乎是更好的解决方案。IssuedDate VARCHAR10,不,不。想想你的数据类型!这完全是错误的。varchar10对studentid来说不是一个糟糕的选择。假设它从不改变,它可能代表一个用户名。例如,它只有10个字节,如果根据ID查询其他表,那么它会保存一个joinNote。另外,按主键分组意味着您实际上没有分组,因此分组方式是浪费时间。^^ true dat,我没有仔细看桌子的设计。我不会使用用户名作为PK,这会造成各种其他复杂性,以确保用户名保持唯一性,并首先进行分配。
IF((@marks > 100.00) OR (@marks < 0.00))
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;