简体   繁体   中英

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

I have a syslog server that inputs its events into a SQL Server database as a varchar . The data looks something like this

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 ...

I am trying to do a count or the number of times any unique error ID comes up. The error ID is always proceeded by "2017" in this case the code is 1009. I am trying to find a way to do a search on that code, or output the 7 lines following the first instance of " 2017 " in the varchar .

I am very new the SQL and there is a good change I am missing some knowledge that would make this easier, but this is my approach, so far.

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
    ...

This finds out if a event is an application error or a system error because this dictates how many more characters there will be until the event ID. I can see this getting very messy from this point forward because following the application or system is a number that can be 1 to 5 digits long. I am hoping there is a better way of doing this.

In SQL Server 2016+ you can use string_split() .

In SQL Server pre-2016, using a CSV Splitter table valued function by Jeff Moden:

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 demo : http://rextester.com/LVS48443

returns:

+----+------------+---------+-------------------------------------------------------------------------+
| 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 ... |
+----+------------+---------+-------------------------------------------------------------------------+

splitting strings reference:


If you need to support varchar(max) input up to a million characters (this modification reduces performance), you can use an alternate by Aaron Bertrand (with ItemNumber added back in) or other string splitting options in the references above:

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





- Sql Cursor:
read about it first, and Make stored procedure and program it to select each line and make string manipulation on it, in this case you got a feature of making String validation and any check you want on the selected text before you be sure of error numbers on it (by the ideas on the previous point).

- Linq Lambda for string manipulation:
use the .net code to loop through the code and use .ToArray() or .ToList() to gather the results.



If i arranged some sample code for you I'll add it here sooner, but start read more about (Sql Cursor, Lambda expression and string manipulation) that will move you up very fast in most of your next tasks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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