我有一个table
的INSERT
触发器,其中table
的一个字段包含一个用逗号分隔的键值对列表,这些键值对用:
分隔
我可以使用下面的语句轻松地将包含两个值的字段选择到临时表中:
-- SAMPLE DATA FOR PRESENTATION ONLY
DECLARE @messageIds VARCHAR(2000) = '29708332:55197,29708329:54683,29708331:54589,29708330:54586,29708327:54543,29708328:54539,29708333:54538,29708334:62162,29708335:56798';
SELECT
SUBSTRING(value, 1,CHARINDEX(':', value) - 1)AS MessageId,
SUBSTRING(value, CHARINDEX(':', value) + 1, LEN(value)-SUBSTRING(value,0,CHARINDEX(value,':'))) AS DeviceId
INTO #temp_messages
FROM STRING_SPLIT(@messageIds, ',')
SELECT * FROM #temp_messages
DROP TABLE #temp_messages
结果将如下所示
29708332 55197
29708329 54683
29708331 54589
29708330 54586
29708327 54543
29708328 54539
29708333 54538
29708334 62162
29708335 56798
从这里我可以join
的临时table
到其他表和insert
的一些结果到第三个table
。
在触发器内部,我可以使用简单的SELECT
语句获取messageIds
,如下所示
DECLARE @messageIds VARCHAR(2000) = (SELECT ProcessMessageIds FROM INSERTED)
现在,我创建临时table
(如上所述)并处理我的
INSERT INto <new_table> SELECT col1, col1, .. FROM #temp_messages
JOIN <another_table> ON ...
不幸的是,这只适用于单行插入,只要有多行插入,我的SELECT ProcessMessageIds FROM INSERTED
就会失败,因为INSERTED表中有多行。
我可以处理CURSOR中的行,但据我所知,CURSORS是触发器中的禁忌,我应该尽可能避免使用它们。
因此,我的问题是,是否有另一种方法可以在trigger
中不使用CURSOR来完成此操作?
3条答案
按热度按时间lnvxswe21#
在讨论解决方案的细节之前,让我指出,如果您规范化了数据库,就不会有这样的问题,正如@Larnu在您的问题的评论部分所指出的那样。
你的
语句假定将有单个值赋给
@messageIDs
,但正如您所指出的,这不一定正确。INSERTED
联接而不是将其加载到变量中然后您可以毫无问题地到达
INSERTED.ProcessMessageIds
。这将不再假设使用了单个值。正如您已经指出的,您可以使用
CURSOR
,但是在触发器内使用游标并不是一个很好的主意,请参见https://social.msdn.microsoft.com/Forums/en-US/87fd1205-4e27-413d-b040-047078b07756/cursor-usages-in-trigger-in-sql-server?forum=aspsqlserver虽然这不需要修改
trigger
,但需要修改插入方式,并且会增加必要的数据库请求数量,所以我建议您不要选择这种方法。参见https://www.simplilearn.com/tutorials/sql-tutorial/what-is-normalization-in-sql
如果您有一个合适的表而不是一个复合值表,就不会有这样的问题,并且通常处理消息id会容易得多。
最好规范化您的表并执行以后需要的重构。现在这是一项巨大的工作,但您将享受其成果。如果这不是一个选项,您可以"当作它已被规范化"并选择解决方案1。
j5fpnvbx2#
你甚至可以比所有讨厌的
CHARINDEX
调用更整洁一点,恕我直言:把它转换成你的触发器
没有局部变量,没有inherent assumptions about single-row inserts,也没有#temp表。
o2g1uqev3#
正如答案中所指出的,使用INSERTED表进行连接解决了我的问题。
我以前从来没有用过“交叉应用”,谢谢。