我想避免可能复制字段值的INSERTS和UPDATES,但并非总是如此。
我有一个varchar字段 Cat_Catalog 。在表目录。
中我可以有两行 Cat_Catalog 的值“123”重复,但我不能有重复字段 Cat_Catalog 以“KAT”字开头(所以我不能有两行“KAT123”Cat_Catalog的值)
我所做的以下触发器无法正常工作,因为将要更新的字段以KAT触发器开始始终引发错误(变量@IfExist始终返回true - 这可能是因为AFTER UPDATE,INSERT语法)。
我想避免使用INSTEAD OF语法,因为更新是由某些API生成的,我没有文档,如果值不以'KAT'开头,我不知道该怎么办。
GO
/****** Object: Trigger [dbo].[Catalog_InsertUpdateCatalog] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--If first three characters are 'KAT'
--then check for duplicate and raiseerror
ALTER TRIGGER [dbo].[Catalog_InsertUpdateCatalog] ON [dbo].[Catalog]
FOR UPDATE,INSERT
AS
set nocount on;
DECLARE @CatalogInsert varchar(50)
DECLARE @IfKat varchar(10) = 'FALSE'
DECLARE @IfExist varchar(10) = 'FALSE'
SELECT @CatalogInsert = Cat_Catalog
FROM inserted
--Does It starts with 'KAT' ?
IF (@CatalogInsert like 'KAT%')
BEGIN
SET @IfKat = 'TRUE'
END
--Check for Duplicate
IF EXISTS(
Select * from Test.dbo.Catalog t
where t.Cat_Catalog = @CatalogInsert
)
BEGIN
SET @IfExist = 'TRUE'
END
IF ( @IfExist = 'TRUE' and @IfKat = 'TRUE' )
BEGIN
RAISERROR ('Catalog allready exists: %s , ISKAT:%s , EXIST:%s', 16, 1, @CatalogInsert, @IfKat, @IfExist);
END
`
问题是我不知道如何检查目录表中已存在的当前值已经存在(必须在更新前检查)。
答案 0 :(得分:1)
请尝试 新版 :
ALTER TRIGGER [dbo].[Catalog_InsertUpdateCatalog] ON [dbo].[Catalog]
FOR UPDATE,INSERT
AS BEGIN
set nocount on;
--Check for Duplicate
IF EXISTS(
Select 1
From (
-- Updated
SELECT
COUNT(*) OVER (PARTITION BY Cat_Catalog) Cnt,
Cat_Catalog
FROM dbo.Catalog
WHERE
Cat_Catalog LIKE 'KAT%'
) t
Join inserted i ON t.Cat_Catalog = i.Cat_Catalog AND Cnt > 1
)
BEGIN
RAISERROR ('Catalog allready exists!', 16, 1);
ROLLBACK TRANSACTION;
END
END
此触发器使用与插入(或更新)行中相同的[Cat_Catalog]字段检查行是否存在。如果存在重复行且[Cat_Catalog]以' KAT'触发RAISE错误+回滚事务。
更新:我改变了触发器。它现在应该正常工作(我测试它)。触发FOR UPDATE,INSERT在表中发生更改后触发。所以我们需要检查表中的重复行。
我通过COUNT(*)OVER(由Cat_Catalog分区)来完成它,但你可以用更熟悉的方式检查它:
SELECT
COUNT(*) Cnt,
Cat_Catalog
FROM
dbo._Catalog
WHERE
Cat_Catalog LIKE 'KAT%'
GROUP BY
Cat_Catalog
答案 1 :(得分:1)
使用CHECK constraint而不是触发器将是一个更好的解决方案,因为触发器在事务中执行得更晚,最终的回滚可能会很昂贵。您可以按如下方式定义检查约束:
[{"date":1454284800,"exercises":[{"name":"Tricep Skull-Crushers","sets":"5","reps":"12","time":"20","weight":"","notes":"testing testing again testing this app which is great "},{"name":"Barbell Squat","sets":"","reps":"","time":"","weight":"","notes":""}]},{"date":1454284800,"exercises":[{"name":"Tricep Skull-Crushers","sets":"5","reps":"12","time":"20","weight":"","notes":"testing testing again testing this app which is great "},{"name":"Barbell Squat","sets":"","reps":"","time":"","weight":"","notes":""},{"name":"Arnold Press","sets":"5","reps":"12","time":"","weight":"","notes":""}]},{"date":1454112000,"exercises":[{"name":"Single Arm Row","sets":"3","reps":"10","time":"","weight":"","notes":""},{"name":"Tricep Rope Pull-Downs","sets":"3","reps":"10","time":"","weight":"","notes":""}]},{"date":1454112000,"exercises":[{"name":"Single Arm Row","sets":"3","reps":"10","time":"","weight":"","notes":""},{"name":"Tricep Rope Pull-Downs","sets":"3","reps":"10","time":"","weight":"","notes":""}]},{"date":1454112000,"exercises":[{"name":"Single Arm Row","sets":"3","reps":"10","time":"","weight":"","notes":""},{"name":"Tricep Rope Pull-Downs","sets":"3","reps":"10","time":"","weight":"","notes":""}]}]
请记住,如果表中已经有重复的“KATxxx”值,则必须删除它们或使用NOCHECK子句创建约束。
答案 2 :(得分:0)
在触发后使用而不是触发。
如果你的问题是反向触发,那么你需要使用NOT Eqals运算符来避免传递这样的错误指示。我应该说
DECLARE @CATALOG_PK BIGINT;
SELECT @CATALOG_PK = CATALOG_PK FROM INSERTED
--Check for Duplicate
IF EXISTS(
Select * from Test.dbo.Catalog t
where t.Cat_Catalog = @CatalogInsert
AND CATALOG_PK <>@CATELOG_PK LIKE t.CATALOG LIKE 'KAT%'
)
BEGIN
SET @IfExist = 'TRUE'
END
然而,如果多次更新或插入完成,这将失败。
答案 3 :(得分:0)
尝试以下两个触发器:
CREATE TRIGGER [MyCatalog_InsertCatalog] ON [dbo].[MyCatalog]
FOR INSERT
AS
IF EXISTS(
SELECT I.*
FROM Inserted I
INNER JOIN MyCatalog M
ON M.Cat_Catalog = I.Cat_Catalog
WHERE I.Cat_Catalog LIKE 'KAT%' )
BEGIN
RAISERROR ('Insert Catalog already exists: ', 16, 1);
ROLLBACK TRANSACTION;
END
GO
CREATE TRIGGER [MyCatalog_UpdateCatalog] ON [dbo].[MyCatalog]
FOR UPDATE
AS
IF EXISTS(
SELECT I.*
FROM Inserted I
INNER JOIN MyCatalog M
ON M.Cat_Catalog = I.Cat_Catalog
INNER JOIN deleted d
ON d.Cat_Id = i.Cat_Id
WHERE I.Cat_Catalog LIKE 'KAT%' AND d.Cat_Catalog <> i.Cat_Catalog)
BEGIN
RAISERROR ('Update Catalog already exists: ', 16, 1);
ROLLBACK TRANSACTION;
END
修改强>
您可以将两个触发器组合成一个:
CREATE TRIGGER [MyCatalog_InsertUpdateCatalog] ON [dbo].[MyCatalog]
FOR INSERT, UPDATE
AS
IF EXISTS(
SELECT I.*
FROM Inserted I
INNER JOIN MyCatalog M
ON M.Cat_Catalog = I.Cat_Catalog
INNER JOIN deleted d
ON d.Cat_Id = i.Cat_Id
WHERE I.Cat_Catalog LIKE 'KAT%' AND d.Cat_Catalog <> i.Cat_Catalog)
BEGIN
RAISERROR ('Update Catalog already exists: ', 16, 1);
ROLLBACK TRANSACTION;
END
ELSE BEGIN
IF EXISTS(
SELECT I.*
FROM Inserted I
INNER JOIN MyCatalog M
ON M.Cat_Catalog = I.Cat_Catalog
WHERE I.Cat_Catalog LIKE 'KAT%' )
BEGIN
RAISERROR ('Insert Catalog already exists: ', 16, 1);
ROLLBACK TRANSACTION;
END
END