5

我的公司有一个记录表,其中包含一个VARCHAR(N)列,其中放置了一个应该是 XML 的字符串,但事实证明它并不总是格式正确的。为了对日志进行分析(以识别错误趋势等),我一直在使用一个LIKE语句。然而,这非常缓慢。

最近,我发现 SQL Server 支持 XQuery,所以我开始使用它。我遇到的问题是我无法找到一种方法来处理CAST/CONVERT我的SELECT陈述中的错误。我最接近的需要 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

一旦遇到格式错误的 XML ,注释的CAST(或替代的 a )将导致查询出错。CONVERT如果我限制为 TOP (N),我可以确保没有错误并且SELECT语句运行得非常快。我只需要一种方法来逐行处理错误。

我考虑过使用TRY/CATCHin IsMatch(),但不能在函数中使用。或者,要使用TRY/CATCH,我考虑了一个存储过程,但我不知道如何将它包含在我的SELECT子句中。

4

1 回答 1

4

如果您被困在 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;
于 2013-02-07T14:17:53.340 回答