2015-06-30 2 views
1

У меня есть таблица журналов, которая содержит столбцы для данных исключения и стека в формате varchar.Есть ли способ группировать строки, используя TSQL

Я хотел бы запросить эту таблицу журналов, чтобы получить количество подобных исключений.

Как объединить аналогичные, но не точные совпадения?

MyApp.MyCustomException: UserId 1 not found 
MyApp.MyCustomException: UserId 2 not found 
MyApp.MyCustomException: UserId 3 not found 
MyApp.MyCustomException: UserId 1 login failed 
MyApp.MyCustomException: UserId 2 login failed 
MyApp.MyCustomException: UserId 3 login failed 

Вышеуказанные 6 рядов следует учитывать как

"MyApp.MyCustomException: UserId not found" Count:3 
"MyApp.MyCustomException: UserId login failed" Count:3 

ЛЕВАЯ функция будет работать на приведенном выше простом примере, но не для исключения такого как NullReferenceException, где может произойти ошибка в нескольких различных местах код.

EDIT: Обновлен пример, чтобы более четко представлять проблему.

ответ

3

я бы просто использовать like с case:

select trace, count(*) 
from (select l.*, 
      (case when trace like 'MyApp.MyCustomException: UserId % not found' 
        then 'MyApp.MyCustomException: UserId not found' 
        when trace like 'MyApp.MyCustomException: UserId % login failed' 
        then 'MyApp.MyCustomException: UserId login failed' 
        else trace 
       end) as canonical_tracer 
     from log l 
    ) l 
group by trace; 
+0

Я мог бы поклясться, что было не законно иметь подстановочный знак в середине строки для подобного предложения !? – user3953989

+0

@ пользователь3953989. , , Это определенно законно. Подстановочные знаки могут появляться в любом месте строки. –

3

Вы можете попробовать использовать

patindex('%pattern%',column) 

Весь выбор может быть что-то вроде

SELECT * FROM tbl 
WHERE patindex('%MyApp.MyCustomException: % not found%',err)>0 

Убедитесь, чтобы не забыть % до и после окончания картины. Функция даст вам положение, в котором шаблон был найден в столбце, или 0, если не найден.

Смотрите здесь для примера: http://sqlfiddle.com/#!3/1a70e/1

Edit:

Это может быть сделано с КТР, как

WITH msgs AS(
SELECT err,CASE 
    WHEN patindex('%MyApp.MyCustomException: % not found%',err)>0 THEN 1 
    WHEN patindex('%Wrong password for %, please try again%',err)>0 THEN 2 
    ELSE 0 END msgno FROM tbl) 
SELECT msgno, MIN(err) msg1, COUNT(*) cnt FROM msgs GROUP BY msgno 

посмотреть здесь: http://sqlfiddle.com/#!3/9565c/2

2. Изменить:

Или, в более общем виде:

WITH pats as (SELECT 'UserId' pat -- define various patterns for 
    UNION ALL SELECT 'IP'   -- words to be removed after ... 
), pos1 AS (      -- find position of pattern 
SELECT pat,err msg,patindex('%'+pat+'%',err)+len(pat) p1 FROM tbl,pats 
), pos2 AS (      -- remove word after pattern 
SELECT LEFT(msg,p1) 
    +'<'+pat+'> ' 
    +SUBSTRING(msg,charindex(' ',SUBSTRING(msg,p1+1,256))+p1,256) msg 
FROM pos1 WHERE p1>len(pat) 
), nonames AS (     -- find non-specific messages 
SELECT err FROM tbl WHERE NOT EXISTS 
    (SELECT 1 FROM pos1 WHERE msg=err AND p1>len(pat)) 
) 
SELECT msg, count(*) cnt FROM -- combine all, group and count 
(SELECT msg FROM pos2 UNION ALL SELECT err FROM nonames) m 
GROUP BY msg 

Из всех сообщений этого удалит первое слово (= последовательность символов без пробелов), появляющееся после того, как один из нескольких предопределенных шаблонов (pat). Это заставит сообщения определенного типа выглядеть одинаково, чтобы их можно было сгруппировать.

Вы можете попробовать его здесь (мое окончательное решение): http://sqlfiddle.com/#!3/a2fb9/4

+0

Спасибо за ответ, не могли бы вы предоставить рабочий пример? – user3953989

+0

Я не знал, что вы можете использовать подстановочные знаки в середине patindex! Могли бы вы также показать, как группировать подсчеты с помощью этой техники? – user3953989

+1

Для группировки вы должны как-то попробовать и «ассимилировать» сообщения, удалив из них userIds. После этого они будут отображаться как «одинаковые значения». Не совсем поняли, как это сделать ... – cars10m

0

Это может выглядеть весьма некрасиво, но это должно быть относительно эффективным. Я использую замену, чтобы избавиться от чисел и дополнительных пробелов перед группировкой. Проверьте это:

WITH yourTable 
AS 
(
    SELECT * 
    FROM 
    (
     VALUES ('MyApp.MyCustomException: UserId 1 not found'), 
       ('MyApp.MyCustomException: UserId 2 not found'), 
       ('MyApp.MyCustomException: UserId 3 not found'), 
       ('MyApp.MyCustomException: UserId 1 login failed'), 
       ('MyApp.MyCustomException: UserId 2 login failed'), 
       ('MyApp.MyCustomException: UserId 3 login failed') 
    ) A(col) 
) 

SELECT generic_col, 
     COUNT(*) AS cnt, 
     'Count: ' + CAST(COUNT(*) AS VARCHAR(25)) AS formatted_cnt 
FROM yourTable 
CROSS APPLY (SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(col,'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''),'0',''),' ',' ')) AS CA(generic_col) 
GROUP BY generic_col 
+1

Единственная проблема в том, что она не всегда будет числом. В других случаях это может быть имя пользователя, ip-адрес или другой тип. Однако это дает мне несколько хороших идей. Благодаря! – user3953989

+0

Это * работает *, если userids состоят только из чисел от 1 до 10, но в общем случае ...? – cars10m

+0

Фактически он обрабатывает цифры отдельно (кроме «10»). Думаю, это должно было быть «0». Вы говорите о других персонажах или диапазоне значений от одного до десяти? – shawnt00

Смежные вопросы