SQL Server创建检测重音符发邮件告警存储过程报错解决
问题根因
- 判断逻辑不合法:原脚本中子查询
SELECT * FROM StudentNames WHERE LastName like '%%'`返回的是匹配的结果集,不是单个标量值,直接在外层套LIKE判断会触发「子查询返回值多于一个」的报错,根本无法执行。 - 触发逻辑缺失:存储过程本身是被动执行的对象,就算判断逻辑写对,也不会在数据插入时自动运行,完全达不到自动告警的要求。
- 邮件调用参数不全:调用
sp_send_dbmail时没有指定必填的邮件配置文件参数,且没有返回具体违规记录,告警可用性差。
可直接运行的实现方案
需要提前在SQL Server实例中配置好Database Mail组件,否则邮件发送功能无法正常工作。
场景1:定时巡检(配合SQL Server代理作业定期执行)
直接用修正后的存储过程即可,替换代码里的邮件配置文件名就能运行:
CREATE PROCEDURE InvalidCharacterCheck AS BEGIN SET NOCOUNT ON; -- 用EXISTS做存在性判断,性能更好且不会触发多值返回报错 IF EXISTS (SELECT 1 FROM StudentNames WHERE LastName LIKE '%`%') BEGIN DECLARE @AlertContent NVARCHAR(MAX) -- 拼接所有违规记录详情,方便直接定位问题 SELECT @AlertContent = STRING_AGG( '记录ID:' + CAST(ID AS NVARCHAR(50)) + ',违规字段值:' + LastName, CHAR(10) ) FROM StudentNames WHERE LastName LIKE '%`%' EXEC msdb.dbo.sp_send_dbmail @profile_name = '你的数据库邮件配置文件名', -- 替换为实际配置的profile名 @recipients = 'Notifyme@gmail.com', @subject = '告警:StudentNames表LastName列检测到重音符(`)无效字符', @body = @AlertContent END ELSE BEGIN PRINT '巡检完成:LastName列当前无无效重音符字符' END END
创建完成后可以在SQL Server代理中新建作业,设置自定义执行周期(比如每1小时)执行EXEC InvalidCharacterCheck,就能实现定期巡检告警。
场景2:实时触发告警(写入数据时立刻检测)
如果需要在插入/更新数据的瞬间就检测并告警,不需要等待定时任务,直接创建AFTER触发器即可,不需要手动调用存储过程:
CREATE TRIGGER trg_CheckInvalidGraveAccent ON StudentNames AFTER INSERT, UPDATE AS BEGIN SET NOCOUNT ON; -- 只检测本次写入/修改的记录,不会扫描全表,性能影响极小 IF EXISTS (SELECT 1 FROM inserted WHERE LastName LIKE '%`%') BEGIN DECLARE @AlertContent NVARCHAR(MAX) SELECT @AlertContent = STRING_AGG( '本次操作涉及违规记录ID:' + CAST(ID AS NVARCHAR(50)) + ',违规字段值:' + LastName, CHAR(10) ) FROM inserted WHERE LastName LIKE '%`%' EXEC msdb.dbo.sp_send_dbmail @profile_name = '你的数据库邮件配置文件名', -- 替换为实际配置的profile名 @recipients = 'Notifyme@gmail.com', @subject = '告警:新写入LastName列包含重音符(`)无效字符', @body = @AlertContent END END
兼容说明:如果使用的是SQL Server 2016及更早版本,不支持
STRING_AGG函数,可以把告警内容拼接部分替换为FOR XML PATH写法,也可以直接去掉内容拼接,发送固定文本的告警邮件。
内容的提问来源于stack exchange,提问作者RPaks
相关产品推荐
相关产品推荐

