繁体   English   中英

您可以从SQL中的长varchar中提取特定的文本字符串吗?

[英]Can you extracting a specific string of text from a long varchar in SQL?

我有一个syslog服务器,它将其事件作为varchar输入到SQL Server数据库中。 数据看起来像这样

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位数字。 我希望有一个更好的方法。

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

在SQL Server 2016之前的版本中,使用Jeff 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


1-让我们首先控制捕捉算法的逻辑:

-我们需要搜索的格式“**:** 2017年”或任何当前年份。 并在相邻的空格“ 1009”之间捕获下一个数字

-在每个会话中使用一个数字(每天,每小时或任何会话定义)在表中插入不同的已收集错误代码。
2-其次,让我们考虑使用替代方法来简化代码。

-SQL游标:
首先阅读它,并进行存储过程和编程,以选择每一行并对其进行字符串操作,在这种情况下,您可以进行字符串验证和对选定文本的任何检查,然后再确定错误编号(根据上一点的想法)。

-用于字符串操作的Linq Lambda:
使用.net代码遍历代码,并使用.ToArray()或.ToList()收集结果。



如果我为您安排了一些示例代码,我会尽快在此处添加,但是开始阅读更多有关(SQL光标,Lambda表达式和字符串操作)的内容,这些内容将使您在大多数下一个任务中快速上手。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM