有没有比RAISEERROR更合适的SQL信息日志记录方案?
方案1:使用PRINT语句(最通用的信息输出方式)
这是SQL Server原生设计用来输出普通消息的语句,语义明确,其他开发者看到就能判断是正常日志输出,不会误以为是故障报错。如果需要拼接变量,有两种常用写法:
- 手动拼接字符串(兼容所有SQL Server版本)
DECLARE @totalrows INT = (SELECT COUNT(*) FROM mytable); DECLARE @fancyrows INT = (SELECT COUNT(*) FROM mytable WHERE fancy = 1); PRINT CAST(@fancyrows AS VARCHAR(10)) + ' rows out of ' + CAST(@totalrows AS VARCHAR(10)) + ' are fancy'; -- 执行后续操作...
- 搭配
FORMATMESSAGE函数(SQL Server 2012及以上版本支持),可以实现和原RAISEERROR一致的占位符格式化效果,代码更简洁:
DECLARE @totalrows INT = (SELECT COUNT(*) FROM mytable); DECLARE @fancyrows INT = (SELECT COUNT(*) FROM mytable WHERE fancy = 1); PRINT FORMATMESSAGE('%i rows out of %i are fancy', @fancyrows, @totalrows); -- 执行后续操作...
注意:默认PRINT的输出会被缓存,缓冲区满了才会批量打印到客户端,如果需要和原RAISEERROR ... WITH NOWAIT一样的实时输出效果,可以参考下面的方案。
方案2:保留实时输出能力的替代写法
如果是长运行脚本,需要实时输出进度不需要等缓存,有两种可选实现:
- 给低严重度
RAISEERROR加明确注释:在语句旁标注清楚是正常日志输出,消除歧义,同时保留实时输出的特性
DECLARE @totalrows INT = (SELECT COUNT(*) FROM mytable); DECLARE @fancyrows INT = (SELECT COUNT(*) FROM mytable WHERE fancy = 1); -- 输出执行进度日志,低严重度不会中断执行 RAISEERROR ('%i rows out of %i are fancy', 10, 1, @fancyrows, @totalrows) WITH NOWAIT; -- 执行后续操作...
- 使用
xp_logevent扩展存储过程:不仅能输出到客户端,还会把消息写入SQL Server错误日志和Windows应用程序日志,适合需要持久化留存的操作日志:
DECLARE @totalrows INT = (SELECT COUNT(*) FROM mytable); DECLARE @fancyrows INT = (SELECT COUNT(*) FROM mytable WHERE fancy = 1); DECLARE @msg VARCHAR(1000) = FORMATMESSAGE('%i rows out of %i are fancy', @fancyrows, @totalrows); -- INFORMATIONAL级别表示为普通信息类日志 EXEC xp_logevent 60000, @msg, INFORMATIONAL; -- 执行后续操作...
方案3:自定义日志表持久化存储
如果需要长期留存脚本执行日志供后续回溯查询,可以自己创建专用的业务日志表,记录时直接插入数据即可,灵活度最高:
-- 首次使用时创建日志表,后续无需重复执行 CREATE TABLE IF NOT EXISTS script_log ( id INT IDENTITY(1,1) PRIMARY KEY, log_time DATETIME DEFAULT GETDATE(), log_level VARCHAR(20) NOT NULL, log_content VARCHAR(MAX) NOT NULL ); GO DECLARE @totalrows INT = (SELECT COUNT(*) FROM mytable); DECLARE @fancyrows INT = (SELECT COUNT(*) FROM mytable WHERE fancy = 1); DECLARE @msg VARCHAR(1000) = FORMATMESSAGE('%i rows out of %i are fancy', @fancyrows, @totalrows); -- 写入自定义日志表 INSERT INTO script_log(log_level, log_content) VALUES ('INFO', @msg); -- 执行后续操作...
其他SQL方言对应实现
如果使用非SQL Server的数据库,也有对应的原生信息输出语法:
- PostgreSQL使用
RAISE NOTICE '信息内容' - MySQL 8.0及以上版本支持
PRINT '信息内容',低版本可以用SELECT '信息内容' AS log;实现
内容的提问来源于stack exchange,提问作者pjpscriv
相关产品推荐
相关产品推荐

