5

私の会社には、 XML であるはずVARCHAR(N)の文字列が配置されている列を含むログ テーブルがありますが、実際には、常に適切な形式であるとは限りません。ロギングの分析 (エラーの傾向の特定など) を実行するために、ステートメントを使用しています。ただし、これは非常に遅いです。LIKE

最近、SQL Server が XQuery をサポートしていることを発見したので、それで遊んでみました。私が直面している問題は、ステートメントCAST/CONVERT内のエラーを処理する方法がわからないことです。SELECT私が最も近いのは、TRY_CONVERT機能があるためSQL Server 2012が必要ですが、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(または代わりにCONVERT) は、不正な形式の XML に遭遇するとすぐにクエリをエラーにします。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 に答える