我的公司有一个包含VARCHAR(N)列的日志表,其中放置了一个应该是
XML的字符串,但事实证明它并不总是格式良好.为了对日志记录进行分析(以识别错误趋势等),我一直在使用LIKE语句.然而,这非常缓慢.
最近,我发现sql Server支持XQuery,所以我开始玩它.我遇到的问题是我无法找到一种方法来处理我的SELECT语句中的CAST / CONVERT错误.我最接近的是需要sql Server 2012,因为它具有TRY_CONVERT功能,但是现在不能从2008 R2升级.
这就是我所拥有的(如果我的公司在2012年运行,这将有效):
CREATE FUNCTION IsMatch( @message AS VARCHAR(MAX),@match AS VARCHAR(MAX),@default AS VARCHAR(MAX)) RETURNS VARCHAR(MAX) AS BEGIN DECLARE @xml XML = TRY_CONVERT(XML,@message) DECLARE @result VARCHAR(MAX) = CASE WHEN @xml IS NOT NULL THEN CASE WHEN @xml.exist('(/FormattedMessage)[contains(.,sql:variable("@match"))]') = 1 THEN @match ELSE @default END ELSE CASE WHEN @message LIKE '%' + @match + '%' THEN @match ELSE @default END END RETURN @result END GO DECLARE @search VARCHAR(MAX) = 'a substring of my xml error message' SELECT Error,COUNT(*) as 'Count' FROM ( SELECT TOP 319 [LogID],[Severity],[Title],[Timestamp],[MachineName],[FormattedMessage] --,CAST([formattedmessage] as xml),IsMatch(@search,'Other') as 'Error' FROM [MyDatabase].[dbo].[Log] (NOLOCK) ) a GROUP BY Error
注释的CAST(或者CONVEERT)会在遇到格式错误的XML时立即导致查询出错.如果我限制为TOP(N),我可以确保没有错误,SELECT语句的工作速度非常快.我只需要一种方法来处理每行错误.
我考虑在Ismatch()中使用TRY / CATCH,但不能在函数中使用.或者,要使用TRY / CATCH,我考虑了存储过程,但我无法弄清楚如何在SELECT子句中包含它.
如果您坚持使用2008 R2,我认为您要做的是在存储过程中使用只读前向CURSOR.然后使用WHILE @@ FETCH_STATUS = 0循环内的TRY CATCH块.
DECLARE logcursor CURSOR FORWARD_ONLY READ_ONLY FOR SELECT TOP 319 [LogId],[formattedmessage] FROM [GenesisLogging].[dbo].[Log] (NOLOCK) OPEN logcursor FETCH NEXT FROM logcursor INTO @id,@formattedmessage WHILE @@FETCH_STATUS = 0 BEGIN BEGIN TRY SET @xml = CONVERT(xml,@formattedmessage) END TRY BEGIN CATCH PRINT @id END CATCH; FETCH NEXT FROM logcursor INTO @id,@formattedmessage END CLOSE logcursor; DEALLOCATE logcursor;