触发器以避免删除SQL Server中该值的最后一行

触发器以避免删除SQL Server中该值的最后一行,sql,sql-server,tsql,sql-server-2012,triggers,Sql,Sql Server,Tsql,Sql Server 2012,Triggers,所以我需要一些帮助,我需要创建一个触发器来避免删除值的最后一行 假设我有: SubjectID | ModuleNr 1792 | 1 1792 | 2 1222 | 3 我希望能够避免删除每个主体的最后一行,因此在这种情况下只删除第一行 我尝试了不同的方法(使用SQLServer2012),但我不能在我的For DELETE之后使用For-Each,也不能在DELETE之前使用For-Each 我尝试的每一种方法都让我删除了行 请记住,这

所以我需要一些帮助,我需要创建一个触发器来避免删除值的最后一行

假设我有:

SubjectID | ModuleNr  
1792      |   1  
1792      |   2  
1222      |   3
我希望能够避免删除每个主体的最后一行,因此在这种情况下只删除第一行

我尝试了不同的方法(使用
SQLServer2012
),但我不能在我的For DELETE之后使用For-Each,也不能在DELETE之前使用For-Each

我尝试的每一种方法都让我删除了行

请记住,这是我在SQL的第一个学期,我是新手

下面是我尝试使用count来查看是否只有1个值:

CREATE TRIGGER curriculum.Keep_Last_Module
ON curriculum.Module
FOR DELETE
AS
BEGIN

DECLARE @count AS INT
SET @count = (SELECT COUNT(*) FROM curriculum.Module 
             WHERE SubjectID = (SELECT SubjectID FROM deleted) GROUP BY SubjectID)

    IF (@count = 1)
    BEGIN
    RAISERROR('Last Module Cannot be Erased',16, 1)
    END
END

提前感谢

我使用了以下触发器,它在一行删除的情况下工作正常,在多行删除的情况下,它将阻止整个删除操作,如果一个主体违反此条件:

CREATE TRIGGER curriculum.Keep_Last_Module
ON curriculum.Module
FOR DELETE
AS
BEGIN

    If exists(SELECT SubjectID FROM deleted except SELECT SubjectID FROM curriculum.module)
      BEGIN
      RAISERROR('Last Module Cannot be Erased',16, 1)
      ROLLBACK
      END
    END
END

我使用了以下触发器,它在一行删除的情况下工作得很好,在多行删除的情况下,它将阻止整个删除操作,如果一个主体违反此条件:

CREATE TRIGGER curriculum.Keep_Last_Module
ON curriculum.Module
FOR DELETE
AS
BEGIN

    If exists(SELECT SubjectID FROM deleted except SELECT SubjectID FROM curriculum.module)
      BEGIN
      RAISERROR('Last Module Cannot be Erased',16, 1)
      ROLLBACK
      END
    END
END

您希望每个主题至少保留一行。计算“之前”和“之后”的受试者人数:

创建触发器课程。保留最后一个模块
论课程模块
而不是删除
像
开始
声明@beforeint;
声明@afterSubjects INT;
选择@beforeSubjects=COUNT(不同的m.subject),
@afterSubjects=COUNT(当d.ModuleNR为NULL时,则为m.subject END时的不同情况)
从课程。模块m左连接
删除d
关于m.ModuleNr=d.ModuleNr
IF(@beforepubjects@afterSubjects)
开始
RAISERROR('无法擦除最后一个模块',16,1)
终止
删除m
从课程模块m加入
删除d
关于m.ModuleNr=d.ModuleNr;
终止

您希望每个主题至少保留一行。计算“之前”和“之后”的受试者人数:

创建触发器课程。保留最后一个模块
论课程模块
而不是删除
像
开始
声明@beforeint;
声明@afterSubjects INT;
选择@beforeSubjects=COUNT(不同的m.subject),
@afterSubjects=COUNT(当d.ModuleNR为NULL时,则为m.subject END时的不同情况)
从课程。模块m左连接
删除d
关于m.ModuleNr=d.ModuleNr
IF(@beforepubjects@afterSubjects)
开始
RAISERROR('无法擦除最后一个模块',16,1)
终止
删除m
从课程模块m加入
删除d
关于m.ModuleNr=d.ModuleNr;
终止

您可以检查
已删除的
中是否存在同一
主体
模块
中没有记录的行,该行的
模块数大于
模块数

CREATE TRIGGER keep_last_module
               ON module
                  FOR DELETE
AS
BEGIN
  IF EXISTS (SELECT *
                    FROM deleted d
                    WHERE NOT EXISTS (SELECT *
                                             FROM module m
                                             WHERE m.subjectid = d.subjectid
                                                   AND m.modulenr > d.modulenr))
  BEGIN
    THROW 50000, 'The last module cannot be deleted.', 0;
  END;
END;

您可以检查
已删除的
中是否存在一行,该行的
模块中没有相同
主题
的记录,该行的
模块数大于
模块数

CREATE TRIGGER keep_last_module
               ON module
                  FOR DELETE
AS
BEGIN
  IF EXISTS (SELECT *
                    FROM deleted d
                    WHERE NOT EXISTS (SELECT *
                                             FROM module m
                                             WHERE m.subjectid = d.subjectid
                                                   AND m.modulenr > d.modulenr))
  BEGIN
    THROW 50000, 'The last module cannot be deleted.', 0;
  END;
END;

您似乎希望它在主题的所有行被删除时自动保留一行

为此,您需要一个
而不是
触发器,如下例()

创建触发器课程。保留最后一个模块
论课程模块
而不是删除
像
开始
与T
AS(选择*,
计数(*)超过(按SubjectID划分)作为BaseSubjectCount
从课程模块中,
D
AS(选择*,
将(按SubjectID划分)上的计数(*)作为DeletedSubjectCount,
MAX(ModuleNr)OVER(按主体划分)作为MAXModuleNr
从(已删除)
删除T
从T
加入D
关于T.SubjectID=d.SubjectID
T.ModuleNr=d.ModuleNr
和(T.BaseSubjectCount D.DeletedSubjectCount
或D.ModuleNr D.MAXModuleNr);
如果@@ROWCOUNT<(从“已删除”中选择“计数(*))
打印“至少忽略了一行,因为这将删除主体的最后一行”
终止

您似乎希望它在删除某个主题的所有行时自动保留一行

为此,您需要一个
而不是
触发器,如下例()

创建触发器课程。保留最后一个模块
论课程模块
而不是删除
像
开始
与T
AS(选择*,
计数(*)超过(按SubjectID划分)作为BaseSubjectCount
从课程模块中,
D
AS(选择*,
将(按SubjectID划分)上的计数(*)作为DeletedSubjectCount,
MAX(ModuleNr)OVER(按主体划分)作为MAXModuleNr
从(已删除)
删除T
从T
加入D
关于T.SubjectID=d.SubjectID
T.ModuleNr=d.ModuleNr
和(T.BaseSubjectCount D.DeletedSubjectCount
或D.ModuleNr D.MAXModuleNr);
如果@@ROWCOUNT<(从“已删除”中选择“计数(*))
打印“至少忽略了一行,因为这将删除主体的最后一行”
终止

@MartinSmith我想你是对的,我会设法解决的。我还编辑了我的答案并提到了这一点。Thanx如果存在,您可以使用
(从已删除中选择SubjectID,从课程.模块中选择SubjectID除外)
而不使用count,其中SubjectID=(从已删除中选择SubjectID)
如果单个语句删除多行,则肯定会失败。您还需要回滚。这是补充的。RAISERROR不会回滚tran,但如果希望它以静默方式更正delete语句,而不是删除最后一个需要INSTEAD OF触发器的语句,并定义要为其执行的逻辑,则抛出preserve@MartinSmi