2009-08-10 4 views
3

У меня есть вопрос анализа данных, который я мог бы легко решить с помощью некоторых T-SQL или некоторых сценариев, но мне было интересно, было ли разумное решение SQL. Проблема в том, что он немного разбирается в предположении независимости от SQL-строк.Подсчет последовательных дубликатов записей с SQL

У меня есть таблица, которая состоит из пар имени-значения, связанные с пользователем и заказанных представлениями, например:

 
ID  USERID VARIABLE  VALUE SUBMITTED 
3115 2287 votech05 2 2009-02-02 15:34:00 
3116 2287 comcol05 1 2009-02-02 15:34:00 
3117 2287 fouryr05 1 2009-02-02 15:35:00 
3118 2287 none05   2 2009-02-02 15:35:00 
3119 2287 ocol1_05 2 2009-02-02 15:44:00 
3120 2287 disnone   2 2009-02-02 15:45:00 
3121 2287 dissense 2 2009-02-02 15:49:00 
3122 2287 dismobil 3 2009-02-02 15:51:00 
3123 2287 dislearn 3 2009-02-02 15:51:00 
3124 2287 disment   3 2009-02-02 15:52:00 
3125 2287 disother 2 2009-02-02 15:55:00 
3126 2287 disrefus 7 2009-02-02 15:58:00 

Я хотел бы быть в состоянии определить стоимость и количество из крупнейших группа идентичных значений (при заказе данных первичный ключ ID). Таким образом, для приведенного выше примера, потому что у меня есть четыре значение = 2 появляется в последовательности, и только три значения = 3, я хотел бы сообщить:

 
USERID  VALUE  COUNT 
2287  2   4 

для данного пользователя.

Опять же, это можно было бы сделать довольно быстро с помощью других инструментов, но поскольку набор данных довольно велик (около 75 миллионов записей) и часто менялся, было бы неплохо решить эту проблему с помощью запроса , Я работаю с SQL Server 2005.

+0

Хорошее название edit, Brian. Благодарю.Я работаю исследователем-исследователем, и его жаргон смещал то, как я думал о проблеме. –

ответ

3

(Edited после комментария)

Вы можете сделать это путем присвоения «головы» номер для каждой группы последовательных значений. После этого вы выбираете номер головы для каждой строки и делаете агрегат на голову.

Вот пример, с КТР для читаемости:

WITH 
OrderedTable as (
    select value, rownr = row_number() over (order by userid, id) 
    from YourTable 
    where userid = 2287 
), 
Heads as (
    select cur.rownr, CurValue = cur.value 
    , headnr = row_number() over (order by cur.rownr) 
    from OrderedTable cur 
    left join OrderedTable prev on cur.rownr = prev.rownr+1 
    where IsNull(prev.value,-1) != cur.value 
), 
ValuesWithHead as (
    select value 
    , HeadNr = (select max(headnr) 
       from Heads 
       where Heads.rownr <= data.rownr) 
    from OrderedTable data 
) 
select Value, [Count] = count(*) 
from ValuesWithHead 
group by HeadNr, value 
order by count(*) desc 

Это Выведет:

Value Count 
2  4 
3  3 
1  2 
2  1 
2  1 
7  1 

Использование "сверху 1", чтобы выбрать только первую строку.

Вот мой запрос для создания тестовых данных:

create table YourTable (
    id int primary key, 
    userid int, 
    variable varchar(25), 
    value int 
) 
insert into YourTable (id, userid, variable, value) values (3115, 2287, 'votech05', 2) 
insert into YourTable (id, userid, variable, value) values (3116, 2287, 'comcol05', 1) 
insert into YourTable (id, userid, variable, value) values (3117, 2287, 'fouryr05', 1) 
insert into YourTable (id, userid, variable, value) values (3118, 2287, 'none05', 2) 
insert into YourTable (id, userid, variable, value) values (3119, 2287, 'ocol1_05', 2) 
insert into YourTable (id, userid, variable, value) values (3120, 2287, 'disnone', 2) 
insert into YourTable (id, userid, variable, value) values (3121, 2287, 'dissense', 2) 
insert into YourTable (id, userid, variable, value) values (3122, 2287, 'dismobil', 3) 
insert into YourTable (id, userid, variable, value) values (3123, 2287, 'dislearn', 3) 
insert into YourTable (id, userid, variable, value) values (3124, 2287, 'disment', 3) 
insert into YourTable (id, userid, variable, value) values (3125, 2287, 'disother', 2) 
insert into YourTable (id, userid, variable, value) values (3126, 2287, 'disrefus', 7) 
+0

Не совсем так, поскольку я не хочу, чтобы общее количество каждого значения, как они кластеризованы, т.е. 2,1,2,2,1,1,2,2,2,2,1,1 вернутся значение = 2, count = 4, а не 7. –

+0

+1, работает после редактирования и лучше, чем с помощью курсора! –

+0

Это выглядит многообещающе. Позвольте мне взглянуть на него. Я бы предпочел не использовать курсоры, если я могу помочь (хотя с этими типами зависимых друг от друга проблем производительность может работать одинаково с использованием CTE). Благодарю. –

2

Это может быть одна из тех проблем, лучше всего решить с курсорами. Попробуй. Он должен быть близок, но он не протестирован, так как вы не предоставили инструкции CREATE TABLE и INSERT с образцами данных, чтобы сделать это легко.

declare @userid int 
set @userid = 2287; 
declare C cursor fast_forward for 
select VALUE from T 
where USERID = @userid 
order by ID; 

declare @value int, @prevvalue int; 
declare @runcount int, @runlongest int; 
set @runlongest = 0; 
declare @valuelongest int; 
open C; 
fetch next from C into @value; 
while @@fetch_status = 0 begin 
    if @value = @prevvalue set @runcount = @runcount + 1 else set @runcount = 1; 
    if @runcount > @runlongest begin 
    set @runlongest = @runcount; 
    set @valuelongest = @value; 
    end; 
    set @prevvalue = @value; 
    fetch next from C into @value; 
end; 
select @userid as USERID, @valuelongest as VALUE, @runlongest as [COUNT]; 

close C; 
deallocate C; 

Он не будет быстрым с 75-миллиметровыми рядами, но он, вероятно, тоже будет слишком медленным. Если ваши прогоны очень длинные, и у вас есть правильные индексы, вы можете добиться большего, указав строки с номером row_number в таблице temp, а затем используя цикл WHILE, который перескакивает через пробег за раз. Дайте мне знать, если вы считаете, что стоит посмотреть (и, если можете, вывести инструкции CREATE TABLE и INSERT с образцами данных).

0

без тестирования я думаю, что следующее должно работать:

row_number() над (раздел по идентификатору пользователя, стоимость заказа по идентификатору)

раз это делается просто выбрать один с самым высоким row_nunber

Пожалуйста, дайте мне знать, если это сработало!

Thanks, Edi

+0

Edi, 1 row_number() не будет работать, потому что он будет обрабатывать последовательные значения так же, как несоответствующие. Здесь важна последовательность значений, а не только то, сколько их есть. –

+0

так значит, это означает, что порядок не может быть определен? Извините, я не понимаю. – 2009-08-10 22:41:35

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