触发器以避免删除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