2013-09-17 2 views
2

немного сложный вопрос SQL (мы запускаем SQL Server 2008 R2).Группировать по, подсчитывать и удалять по последовательным записям

Из таблицы журналов Мне нужно объединить последовательные записи, содержащие одни и те же сообщения, для подсчета количества сообщений и удаления комбинированных сообщений.

Чтобы сделать это более понятным и видимым, вот небольшой пример данных

ID DATE  MSG COUNT 
1 2013-08-17 mail NULL 
2 2013-08-17 mail NULL 
3 2013-08-17 www NULL 
4 2013-08-18 www NULL 
5 2013-08-18 www NULL 
6 2013-08-18 www NULL 
7 2013-08-18 mail NULL 
8 2013-08-18 www NULL 
9 2013-08-19 mail NULL 
10 2013-08-19 mail NULL 
11 2013-08-20 mail NULL 
12 2013-08-20 mail NULL 
13 2013-08-21 www NULL 
14 2013-08-22 mail NULL 
15 2013-08-22 mail NULL 
16 2013-08-23 mail NULL 
17 2013-08-23 mail NULL 
18 2013-08-23 mail NULL 

Результат должен выглядеть следующим образом

ID DATE  MSG COUNT 
1 2013-08-17 mail NULL 
2 2013-08-17 mail NULL 
3 2013-08-17 www NULL 
6 2013-08-18 www 3 
7 2013-08-18 mail 1 
8 2013-08-18 www 1 
12 2013-08-20 mail 4 
13 2013-08-21 www 1 
15 2013-08-22 mail 2 
16 2013-08-23 mail NULL 
17 2013-08-23 mail NULL 
18 2013-08-23 mail NULL 

Итак, в основном запрос должен

  1. обрабатывать данные только в пределах заданного диапазона дат (в этом примере с 2013-08-18 по 2013-08-22)
  2. объединить последовательные строки на основе текста поля MSG
  3. рассчитывать объединенные данные и установите значение в поле Count
  4. удалить объединенные записи (в данном примере, например, ID 6 остается, но ID 5 и ИД 4 должны быть удалены)

Я не являюсь экспертом в SQL я был бы очень признателен за любую помощь, предложения или SQL запросов

заранее спасибо ...

+0

Можете ли вы создать SQLFiddle? Нам было бы намного легче помочь вам. – Minoru

+0

Вы ищете последовательные записи или записи в одну и ту же дату, поскольку в запросе выше кажется, что записи (столбец MSG) сгруппированы по дате. –

+0

Я ищу последовательные записи с тем же MSG (Message), а не Date. Извините за путаницу – padre

ответ

1

Моя идея заключается в том, чтобы сделать это с 2 запросы:

(i) Первый должен был только учитывать и обновлять записи.

(II) Второй был удалить все записи, данные диапазон дат, который имел значение NULL на COUNT колонке.

EDIT: Я сделал шаг (I), но я не мог сделать это сохранить значение NULLCOUNT для тех, которые будут удалены. Он обновляет все строки с помощью COUNT. Теперь вам нужно только DELETE правых строк.

Шаг (я):

(для MySQL)

UPDATE tab ta JOIN 
    (SELECT date, msg, COUNT(*) AS cnt FROM tab GROUP BY date, msg) tb 
SET ta.count = tb.cnt 
WHERE ta.date = tb.date AND ta.msg = tb.msg AND 
ta.date BETWEEN 
    DATE('2013-08-18') AND DATE('2013-08-21'); 

PS: Синтаксис DATE Я использовал для MySQL, вы можете адаптировать его для MS SQL Server.

(для MS SQL Server)

UPDATE ta 
SET ta.count = tb.cnt 
FROM tab ta, 
    (SELECT date, msg, COUNT(*) AS cnt FROM tab GROUP BY date, msg) tb 
WHERE ta.date = tb.date AND ta.msg = tb.msg AND ta.date 
BETWEEN CAST('2013-08-18' AS DATE) AND CAST('2013-08-20' AS DATE); 
+0

Я не думаю, что это отвечает на вопрос. – Jerry

+0

Он также попросил ** предложения **. Итак ... Я думаю, что это приемлемо. – Minoru

+0

если вы могли бы помочь мне с кодом SQL для (i), я мог бы обрабатывать (ii) – padre

1

Попробуйте это:

DROP TABLE #temp 
GO 
select 
    * 
into #temp 
from (
    select '1' as id,'2013-08-17' as [date], 'mail' as msg,'NULL' as [count] union all 
    select '2','2013-08-17','mail','NULL' union all 
    select '3','2013-08-17','www','NULL' union all 
    select '4','2013-08-18','www','NULL' union all 
    select '5','2013-08-18','www','NULL' union all 
    select '6','2013-08-18','www','NULL' union all 
    select '7','2013-08-18','mail','NULL' union all 
    select '8','2013-08-18','www','NULL' union all 
    select '9','2013-08-19','mail','NULL' union all 
    select '10','2013-08-19','mail','NULL' union all 
    select '11','2013-08-20','mail','NULL' union all 
    select '12','2013-08-20','mail','NULL' union all 
    select '13','2013-08-21','www','NULL' union all 
    select '14','2013-08-22','mail','NULL' union all 
    select '15','2013-08-22','mail','NULL' union all 
    select '16','2013-08-23','mail','NULL' union all 
    select '17','2013-08-23','mail','NULL' union all 
    select '18','2013-08-23','mail','NULL' 
) x 
GO 


select 
    t.*, 
    rwn 
from #temp t 
join (
    select 
     id, [date], [msg], [rwn] = row_number() over(partition by [date], [msg] order by id) 
    from #temp 
    where 1=1 
     and [date] between '2013-08-18' and '2013-08-22' 
) x 
    on t.id=x.id 
order by 
    t.date, t.msg 

Просто измените его для UPDATE, а затем удалить все строки, где RWn> 1

EDIT: Ваши данные тип - это, вероятно, текст, поэтому вы получаете сортировку/сравнение ошибок. Вам действительно нужен текст? Это большой тип данных объекта (blob), который может хранить несколько ГБ текста. Попробуйте изменить это на varchar (8000), например, или, если это действительно то, что большие сообщения, varchar (max) будет делать тоже

+0

У меня есть эта ошибка: текстовые, текстовые и графические типы данных не могут сравниваться или сортироваться, кроме случаев, когда используется оператор NULL или LIKE. – padre

+0

Он жалуется: (раздел по DATUM, порядок MSG по id). Если я удалю MSG из Query, то я не получу никаких ошибок, но также нет результатов. – padre

+0

MSG, вероятно, определен как «текст», который вы не можете сортировать или группировать. Попробуйте использовать его для varchar (max) 'like:' cast (msg как varchar (max)) ' –

1

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

DECLARE @Table_2 TABLE (ID INT, [DATE] date, MSG Varchar(50), [COUNT] int) 
Declare @fromDate as date = '2013-08-18' 
Declare @toDate as date = '2013-08-22' 

INSERT INTO @Table_2 (ID, [DATE], MSG, [COUNT]) 
SELECT  MAX(DISTINCT ID) AS ID, DATE, MSG, COUNT(DATE) AS COUNT 
FROM   dbo.Table_1 
where [DATE] between @fromDate and @toDate 
GROUP BY DATE, MSG 



UPDATE Table_1 
SET [COUNT] = T2.COUNT 

FROM Table_1 AS T1 INNER JOIN 
@Table_2 AS T2 
ON T1.ID = T2.ID 

WHERE T1.ID = T2.ID 


DELETE T1 
FROM Table_1 AS T1 
FULL OUTER JOIN @Table_2 AS T2 
ON T1.DATE = T2.DATE AND T1.MSG = T2.MSG 

WHERE (T1.DATE = T2.DATE AND T1.MSG = T2.MSG) AND T1.ID != T2.ID 
Смежные вопросы