2009-08-22 2 views
0

Это мои входные данныеКак сделать это преобразование данных

GroupId Serial Action 
1  1  Start 
1  2  Run 
1  3  Jump 
1  8  End 
2  9  Shop 
2  10  Start 
2  11  Run 

Для каждого activitysequence в группе я хочу найти пары действий, где Action1.SerialNo = Action2.SerialNo + к и как раз может это происходит

Suppose k = 1, then output will be 

FirstAction NextAction Frequency 
Start Run 2 
Run Jump 1 
Shop Start 1 

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

ответ

1

tful. Это должно привести к желаемому результату, но я не знаю, будет ли это так быстро, как вам бы хотелось. Стоит попробовать.

create table Actions(
    GroupId int, 
    Serial int, 
    "Action" varchar(20) not null, 
    primary key (GroupId, Serial) 
); 

insert into Actions values 
    (1,1,'Start'), (1,2,'Run'), (1,3,'Jump'), 
    (1,8,'End'), (2,9,'Shop'), (2,10,'Start'), 
    (2,11,'Run'); 
go 

declare @k int = 1; 
with ActionsDoubled(Serial,Tag,"Action") as (
    select 
    Serial, 'a', "Action" 
    from Actions as A 
    union all 
    select 
    [email protected], 'b', "Action" 
    from Actions 
    as B 
), Pivoted(Serial,a,b) as (
    select Serial,a,b 
    from ActionsDoubled 
    pivot (
    max("Action") for Tag in ([a],[b]) 
) as P 
) 
    select 
    a, b, count(*) as ct 
    from Pivoted 
    where a is not NULL and b is not NULL 
    group by a,b 
    order by a,b; 
go 

drop table Actions; 

Если вы будете делать то же вычисление для различных значений @k на стабильных данных, это может работать лучше в долгосрочной перспективе:

declare @k int = 1; 
    select 
    Serial, 'a' as Tag, "Action" 
    into ActionsDoubled 
    from Actions as A 
    union all 
    select 
    [email protected], 'b', "Action" 
    from Actions 
    as B; 
go 

create unique clustered index AD_S on ActionsDoubled(Serial,Tag); 
create index AD_a on ActionsDoubled(Tag,Serial); 
go 

with Pivoted(Serial,a,b) as (
    select Serial,a,b 
    from ActionsDoubled 
    pivot (
    max("Action") for Tag in ([a],[b]) 
) as P 
) 
    select 
    a, b, count(*) as ct 
    from Pivoted 
    where a is not NULL and b is not NULL 
    group by a,b 
    order by a,b; 
go 

drop table ActionsDoubled; 
+0

Это действительно прекрасно сработало для меня. Большое спасибо. –

0
SELECT a1.Action AS FirstActio, a2.Action AS NextAction, COUNT(*) AS Frequency 
FROM Activities a1 JOIN Activities a2 
ON (a1.GroupId = a2.GroupId AND a1.Serial = a2.Serial + @k) 
GROUP BY a1.Action, a2.Action; 
+0

Но что действительно «достаточно быстро»? Разве это все равно не закончит сканирование таблицы всего 1 миллион строк (а затем и некоторых)? – hythlodayr

+0

спасибо, но это занимает много времени для моих данных, как сделать это быстрее? –

0

Проблема заключается в следующем: ваш запрос должен проходить КАЖДУЮ строку независимо.

Вы можете сделать его более управляемым для своей базы данных, решая каждую группу отдельно как отдельные запросы. Особенно, если размер каждой группы мал.

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

Так, например:

--Stickler for clean formatting... 
SELECT 
    a1.Action AS FirstAction, 
    a2.Action AS NextAction, 
    COUNT(*) AS Frequency 
FROM 
    Activities a1 JOIN Activities a2 
    ON (a1.groupid = a2.groupid 
     AND a1.Serial = a2.Serial + @k) 
WHERE 
    a1.groupid = 1 
GROUP BY 
    a1.Action, 
    a2.Action; 

Кстати, у вас есть индекс (GroupID, последовательный) на столе, не так ли?