触发器定义中的 DELETE 语句问题
Posted
技术标签:
【中文标题】触发器定义中的 DELETE 语句问题【英文标题】:DELETE statement issues within a trigger definition 【发布时间】:2012-08-01 21:18:00 【问题描述】:我创建了一个插入/更新触发器,旨在根据插入的数据更新不同表中的信息。触发器做(或应该做)的最后一件事是从目标表中删除所有数据,条件可能在触发器的插入部分发生变化。
除了最后的DELETE
语句外,一切似乎都在使用触发器。它正在执行 DELETE
语句,但不遵循 where 子句中的任何条件。它只是删除表中的所有内容。
我什至尝试将 where 子句中的 NOT IN
更改为 IN
,但仍然如此。我已经隔离了DELETE
语句并在触发器之外进行了测试,它工作正常(使用相同的变量和子查询)。
我是否遗漏了触发器的行为?
代码来了:
ALTER TRIGGER [dbo].[cust_trgr_profile_attribute]
ON [dbo].[port_module_instance_setting]
AFTER INSERT, UPDATE
AS
DECLARE @ModuleId INT=449,
@MatchGroupModSetting VARCHAR(50) = 'AttributeGroup',
@FilterGroupModSetting VARCHAR(50) = 'FilterAttributeGroup',
@MatchAttributes TABLE (attribute_id INT),
@FilterAttributes TABLE (attribute_id INT)
INSERT INTO @MatchAttributes
SELECT DISTINCT camatch.attribute_id
FROM inserted I
JOIN core_attribute camatch ON I.value = CONVERT(VARCHAR(10), camatch.attribute_group_id)
JOIN port_module_instance pmi ON I.module_instance_id = pmi.module_instance_id
AND pmi.module_id=@ModuleId
WHERE I.name like @MatchGroupModSetting+'_'
INSERT INTO @FilterAttributes
SELECT DISTINCT cafilter.attribute_id
FROM inserted I
JOIN core_attribute cafilter ON I.value = CONVERT(VARCHAR(10), cafilter.attribute_group_id)
JOIN port_module_instance pmi ON I.module_instance_id = pmi.module_instance_id
AND pmi.module_id=@ModuleId
WHERE I.name=@FilterGroupModSetting
IF ((SELECT COUNT(*) FROM @MatchAttributes) > 0 OR (SELECT COUNT(*) FROM @FilterAttributes) > 0)
BEGIN
IF (SELECT COUNT(*) FROM @MatchAttributes) > 0
BEGIN
UPDATE cpa
SET cpa.[required]=0
FROM cust_profile_attribute cpa
JOIN @MatchAttributes ma ON cpa.attribute_id = ma.attribute_id
END
IF (SELECT COUNT(*) FROM @FilterAttributes) > 0
BEGIN
UPDATE cpa
SET cpa.[required]=0
FROM cust_profile_attribute cpa
JOIN @FilterAttributes fa ON cpa.attribute_id=fa.attribute_id
END
DELETE FROM cust_profile_attribute
WHERE attribute_id NOT IN (SELECT distinct ca.attribute_id
FROM core_attribute ca
JOIN port_module_instance_setting inst ON CONVERT(VARCHAR(10),ca.attribute_group_id) = inst.value
JOIN port_module_instance modinst ON inst.module_instance_id = modinst.module_instance_id
AND modinst.module_id = @ModuleId
WHERE inst.name like @MatchGroupModSetting + '_'
OR inst.name like @FilterGroupModSetting)
END
【问题讨论】:
人们可以从微软风格的@
中猜到,但是当您知道时,为什么还要强迫人们猜测您的 RDBMS?
欧文,我为我的无知道歉,但我不太清楚你的意思。你是说我需要说一下这是一个 MSSQL 设置吗?
attribute_id 可以为 NULL 吗?使用 NOT EXISTS 或 LEFT OUTER JOIN 比 NOT IN 好得多。
尝试在最后的SELECT
中使用列上的适当别名来限定distinct attribute_id
。只是看起来模棱两可。
Erwin Brandstetter 可能意味着建议您在您的问题中添加适当的 标签,该问题现已添加 (sql-server
)。而且我们倾向于不将产品名称放在问题标题中,因为我们通常有相应的标签。 (从标题中删除了(MSSQL)
。)
【参考方案1】:
我发现触发器工作原理的基本逻辑存在缺陷。我现在已经完善了对正在发生的事情的理解,并且能够阐明更多信息以供他人帮助。与其尝试完全改变原始帖子,我认为最好在此处发布新信息。
基本思想是port_module_instance_setting
表在 中存储一个字符串,表示一个设置(在这种特定情况下,设置条件以使value
字段始终是一个数字)。我想要完成的是,当value
字段在这些特定“设置”之一中更新时,旧value
引用的cust_profile_attribute
表中的所有内容都会被删除。在此上下文中,port_module_instance_setting
的 value
字段是直接引用 core_attribute
的 attribute_group_id
的数字 varchar 值。请不要评论有关使用不同数据类型引用表的最佳实践,因为我无法控制实际的表结构:)
除了末尾的DELETE
语句外,触发器中的所有内容都正常运行。它什么也没做。关于它为什么不删除我想要的属性的任何想法?
我已将DELETE
语句更改如下,以引用预先更新的value
字段。
DELETE FROM cust_profile_attribute
WHERE attribute_id IN(SELECT ISNULL(attribute_id,-1) FROM deleted d
JOIN core_attribute ca ON ca.attribute_group_id= CONVERT(INT,d.value))
【讨论】:
以上是关于触发器定义中的 DELETE 语句问题的主要内容,如果未能解决你的问题,请参考以下文章