我想创建一个触发器来检查在插入之前是否存在记录,如果它存在回滚,如果不继续执行插入。 事情是当我做插入它总是回滚。 我该怎么办?
ALTER TRIGGER [dbo].[CHECKCONSOMMATION]
ON [dbo].[ConsommationEau]
FOR INSERT
AS
DECLARE @IDABONNEMENT INT
DECLARE @DEFMONTH DATETIME
SELECT @IDABONNEMENT = inserted.idAbonnement FROM inserted
SELECT @DEFMONTH = inserted.Periode FROM inserted
IF EXISTS (SELECT 1 FROM ConsommationEau WHERE idAbonnement = @IDABONNEMENT AND DATEDIFF(MONTH, Periode, @DEFMONTH) = 0)
BEGIN
RAISERROR('THIS RECORD IS ALREADY EXISTS', 10, 1)
ROLLBACK
RETURN
END
这是我的桌子。
USE [GESTEAU]
GO
/****** Object: Table [dbo].[ConsommationEau] Script Date: 4/20/2017
:08:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ConsommationEau](
[idConsomationEau] [int] IDENTITY(1,1) NOT NULL,
[Periode] [date] NULL,
[Qte] [int] NULL,
[idAbonnement] [int] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ConsommationEau] WITH CHECK ADD FOREIGN
KEY([idAbonnement])
REFERENCES [dbo].[AbonnementEau] ([idAbonnement])
GO
答案 0 :(得分:4)
如果意图是每个月只能包含一行idAbonnement
,那么我就不会使用触发器。我使用了持久计算列和唯一索引:
CREATE TABLE [dbo].[ConsommationEau](
[idConsomationEau] [int] IDENTITY(1,1) NOT NULL,
[Periode] [date] NULL,
[Qte] [int] NULL,
[idAbonnement] [int] NULL,
PeriodeMonth as DATEADD(month,DATEDIFF(month,0,Periode),0) persisted
) ON [PRIMARY]
GO
create unique index IX_ConsommationEau_Monthly
on ConsommationEau (idAbonnement, PeriodeMonth)
这样,您宣布应该是唯一的,而不必编写程序代码,并且您已经避免了当前触发器的问题它目前没有正确处理多行插入的地方。
(计算列定义中的DATEADD
/ DATEDIFF
对只是确保一个月内的任何日期转换为同月的第一天,并且是我通常首选的调整日期的方法(时间)值)
要在触发器内执行此操作,您必须意识到FOR INSERT
触发器也称为AFTER
触发器。您总是会找到一条与刚插入的行匹配的行,因为在触发器触发时,它们已经被添加到表中 - 行匹配自己
通常情况下,如果您想阻止插入行,我建议您使用INSTEAD
触发器来阻止它们出现在最终表格中。但是,这可能变得很尴尬 - 特别是因为很容易忘记两个冲突的行可能不是新插入的行和现有的行,而是两个新插入的行。
因此,我们会坚持FOR INSERT
触发器。我们所需要的只是:
ALTER TRIGGER [dbo].[CHECKCONSOMMATION]
ON [dbo].[ConsommationEau]
FOR INSERT
AS
IF EXISTS(
SELECT * FROM ConsommationEau WHERE
idAbonnement IN (SELECT idAbonnement FROM inserted)
GROUP BY idAbonnement,DATEADD(month,DATEDIFF(month,0,Periode),0)
HAVING COUNT(*) > 1)
BEGIN
RAISERROR('THIS RECORD IS ALREADY EXISTS', 10, 1)
ROLLBACK
END
(但请注意,这已经转变为表格中的一个简单的唯一性测试,正如您所观察到的那样,使用为此设计的构造更加整齐地执行,如我上面的第一个解决方案中所使用的)< / p>
答案 1 :(得分:1)
在IF之后使用关键字BEGIN和END,以确保ROLLBACK计算IF。
IF EXISTS [condition]
BEGIN
RAISERROR('Error',10,1)
ROLLBACK
RETURN
END
但大多数情况下,我建议你在表格定义中使用检查约束:
https://stackoverflow.com/a/2570810/3635715
Microsoft参考:
https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-table-column-constraint-transact-sql
答案 2 :(得分:0)
如果匹配不匹配,则应使用INSTEAD OF触发器进行插入:
ALTER TRIGGER [dbo].[CHECKCONSOMMATION]
ON [dbo].[ConsommationEau]
Instead of INSERT
AS
MERGE ConsommationEau c
USING inserted i
on c.idAbonnement = i.idAbonnement AND DATEDIFF(MONTH, c.Periode, i.Periode) = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT ([idConsomationEau, [Periode], [Qte], [idAbonnement])
VALUES (i.[idConsomationEau, i.[Periode], i.[Qte], i.[idAbonnement])