2017-05-04 136 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表达式和字符串操作),将你大部分的你的下一个任务非常快拉升。

相关问题