Как сделать это преобразование данных - PullRequest
0 голосов
/ 22 августа 2009

Это мои входные данные

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

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

Suppose k  = 1, then output will be

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

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

Ответы [ 3 ]

1 голос
/ 22 августа 2009

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
    Serial-@k, '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
    Serial-@k, '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 голосов
/ 22 августа 2009

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

Вы можете сделать ее более управляемой для вашей базы данных, рассматривая каждую группу отдельно как отдельные запросы. Особенно если размер каждой группы МАЛЕНЬКИЙ.

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

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

--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, Serial) в таблице, верно?

0 голосов
/ 22 августа 2009
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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...