2017-05-04 139 views
0

我有一個系統日誌服務器,它將事件輸入到SQL Server數據庫中作爲varchar。數據看起來像這樣你可以從SQL中的long varchar提取特定的文本字符串嗎?

Apr 27 22:03:38 ServerName MSWinEventLog 3 Application 4217 Thu Apr 27 22:03:30 2017 1009 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... 

我想要做一個計數或任何唯一的錯誤ID出現的次數。錯誤ID始終以「2017」開頭,在這種情況下,代碼爲1009.我試圖找到一種方法來搜索該代碼,或輸出varchar中「2017」的第一個實例後面的7行。

我是非常新的SQL,並且有一個很好的改變,我錯過了一些可以使這更容易的知識,但這是我的方法,到目前爲止。

SELECT 
    COUNT([key]) AS CountofErrors, 
    MAX(MSGTEXT) AS FULLMessage, 
    CASE 
     WHEN (CASE 
       WHEN LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 12) LIKE 'a%' 
        THEN LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 11) 
        ELSE RIGHT(LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 12), 11) 
      END) LIKE 's%' 
      THEN LEFT(LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 52), 12), 6) 
      ELSE (CASE 
        WHEN LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 12) LIKE 'a%' 
         THEN LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 11) 
         ELSE RIGHT(LEFT(RIGHT(MSGTEXT, LEN(MSGTEXT) - 51), 12), 11) 
       END) 
     END AS system2 
FROM 
    SyslogDatabase 
WHERE 
    ... 
GROUP BY 
    ... 

此發現如果一個事件是一個應用程序錯誤或系統錯誤,因爲這決定了有多少個字符會出現,直到事件ID。我可以看到,從這一點來看,這變得非常混亂,因爲遵循應用程序或系統是一個數字,可以是1到5位數字。我希望有一個更好的方法來做到這一點。

回答

0

在SQL Server 2016+中,您可以使用string_split()

在SQL Server預-2016,採用由傑夫MODEN一個CSV分路器表值函數:

create table t (id int not null identity(1,1), msgtext varchar(8000)) 
insert into t values 
('Apr 27 22:03:38 ServerName MSWinEventLog 3 Application 4217 Thu Apr 27 22:03:30 
2017 1009 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... 
2017 1009 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... 
2017 1010 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ...') 

select 
    t.id 
    , s.ItemNumber 
    , ErrorId = left(s.Item,charindex(' ',s.Item+' ')-1) 
    , s.Item 
from t 
    cross apply dbo.delimitedsplit8k(replace(t.msgtext,'2017 ',char(30)),char(30)) s 
where s.Item like '[0-9]%' 

rextester 演示http://rextester.com/LVS48443

回報:

+----+------------+---------+-------------------------------------------------------------------------+ 
| id | ItemNumber | ErrorId |         Item         | 
+----+------------+---------+-------------------------------------------------------------------------+ 
| 1 |   2 | 1009 | 1009 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... | 
| 1 |   3 | 1009 | 1009 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... | 
| 1 |   4 | 1010 | 1010 MSExchangeHM N/A Error ServerName 2 Microsoft Exchange Health ... | 
+----+------------+---------+-------------------------------------------------------------------------+ 

分割字符串參考:


如果需要支持varchar(max)輸入多達一百萬個字符(此修飾降低性能),可以通過使用替代Aaron Bertrand(加入ItemNumber)或上述參考文獻中的其他字符串分割選項:

create function dbo.SplitStrings_Moden (@list varchar(max), @delimiter varchar(255)) 
returns table with schemabinding as return 
    with e1(n)  as (select 1 union all select 1 union all select 1 union all select 1 
         union all select 1 union all select 1 union all select 1 
         union all select 1 union all select 1 union all select 1), 
     e2(n)  as (select 1 from e1 a, e1 b), 
     e4(n)  as (select 1 from e2 a, e2 b), 
     e42(n)  as (select 1 from e4 a, e2 b), 
     ctetally(n) as (select 0 union all select top (datalength(isnull(@list,1))) 
         row_number() over (order by (select null)) from e42), 
     ctestart(n1) as (select t.n+1 from ctetally t 
         where (substring(@list,t.n,1) = @delimiter or t.n = 0)) 
    select 
     ItemNumber = row_number() over(order by s.n1) 
    , Item = substring(@list, s.n1, isnull(nullif(charindex(@delimiter,@list,s.n1),0)-s.n1,8000)) 
    from ctestart s; 
go 
+0

感謝您的幫助,我接受了您的建議。出於某種原因,當我搜索「2007」時,我無法正確地獲得結果,但是當我搜索該月份時,我得到了它的工作。我想我必須更多地瞭解這個定界的split8K函數的工作原理,然後才能弄清楚爲什麼它不能很好地工作。 –

+0

@ J.Johnson它取決於你使用了哪個函數。我用於rextester演示的函數是'delimitedsplit8k'的原始版本,分隔符僅限於'char(1)',這就是爲什麼我用'char(30)'替換'2017'字符串並分割在'char(30)'上代替。如果你使用了我的答案底部的第二個函數('SplitStrings_Moden'),它支持更長的分隔符('varchar(255)')。 。 – SqlZim

0


1-讓我們先來控制捕算法邏輯:

- 我們需要尋找 「** :** 2017年」 的格式或任何當前年份。並捕獲下一個數字「1009」

- 使用每個會話的數字(每天,每小時或任何會話定義)在表中插入不同的收集的err號碼。

2-讓我們再次思考使用替代方法簡化代碼。

-Sql光標:
首先閱讀它,然後製作存儲過程並對其進行編程以選擇每一行並對其進行字符串操作,在這種情況下,您獲得了對字符串進行驗證以及在選定的文本,然後再確定其中的錯誤編號(通過前一點的想法)。

- 用於字符串處理的Linq Lambda:
使用.NET代碼循環訪問代碼,並使用.ToArray()或.ToList()來收集結果。



如果我安排了一些示例代碼爲你,我會在這裏越早添加,但開始閱讀更多關於(SQL遊標,Lambda表達式和字符串操作),將你大部分的你的下一個任務非常快拉昇。

相關問題