2009-08-18 8 views
2

rangées Données:Regroupement consécutif "wins" dans une rangée

symbol_id profit date 
1   100 2009-08-18 01:01:00 
1   100 2009-08-18 01:01:01 
2   80  2009-08-18 01:01:02 
2   -10 2009-08-18 01:01:03 
1   156 2009-08-18 01:01:04 
2   98  2009-08-18 01:01:05 
1   -56 2009-08-18 01:01:06 
1   18  2009-08-18 01:01:07 
3   234 2009-08-18 01:01:08 
3   167 2009-08-18 01:01:09 
3   34  2009-08-18 01:01:10 

Je cherche la moyenne et les plus grandes runs/stries de victoires (profit> = 0) et pertes (profits < 0) par SYMBOL_ID.

Regarder juste SYMBOL_ID = 1:

symbol_id profit date 
1   100 2009-08-18 01:01:00 
1   100 2009-08-18 01:01:01 
1   156 2009-08-18 01:01:04 
1   -56 2009-08-18 01:01:06 
1   18  2009-08-18 01:01:07 

vous pouvez le voir il y a 3 consécutifs "victoires", puis une "perte", puis une "victoire"

moyenne de 2 victoires ((3 + 1)/2)
plus grande série de 3
est moyenne de 1 perte (1/1)
plus grand strie est une

requête souhaitée Résultat:

symbol_id avg_winning_streak largest_winning avg_losing_streak largest_losing_streak 
1   2     3    1     1 
2   1     1    1     1 
3   3     3    0     0 

Répondre

1
SELECT symbol_id, 
     COALESCE(AVG(IF(res, cnt, NULL)), 0) AS avgwin, 
     COALESCE(MAX(IF(res, cnt, NULL)), 0) AS maxwin, 
     COALESCE(AVG(IF(NOT res, cnt, NULL)), 0) AS avglose, 
     COALESCE(MAX(IF(NOT res, cnt, NULL)), 0) AS maxlose 
FROM (
     SELECT symbol_id, streak, COUNT(*) AS cnt, res 
     FROM (
       SELECT g.*, 
         @streak := @streak + ((profit > 0) XOR @result) AS streak, 
         @result := (profit > 0) AS res 
       FROM (
         SELECT @streak := 0, 
           @result := false 
         ) vars, 
         t_game g 
       ORDER BY 
         symbol_id, date 
       ) q 
     GROUP BY 
       symbol_id, streak 
     ) q2 
GROUP BY 
     symbol_id 
+0

En fait, j'ai trouvé une autre réponse de votre faire quelque chose de très similaire. Il en a modifié quelques-uns et l'a surtout fonctionné ... mais cela fonctionne tel quel. Merci! –

2

J'ai écrit une solution pour SQL Server 2005 ou version ultérieure. C'est du SQL standard mais je ne sais pas si MySQL supporte row_number(). Vous pouvez remplacer les CTE par des sous-requêtes si besoin est.

Notez que je considère un gain de zéro comme une victoire et une perte, ce qui n'est qu'une façon de gérer les zéros. Vous pouvez modifier les inégalités dans ces deux lignes à compter les zéros différemment:

case when sp>=0 then 1.0*count(*) end as win_run_len_decimal, 
case when sp<=0 then 1.0*count(*) end as loss_run_len_decimal 

est ici la requête complète:

with Trk as (
    select 
    symbol_id, 
    sign(profit) as sp, 
    row_number() over (
     partition by symbol_id 
     order by d 
    ) as rk, 
    row_number() over (
     partition by symbol_id,sign(profit) 
     order by d 
    ) as rksp 
    from T 
), Trk_agg as (
    select 
    symbol_id, 
    sp, 
    case when sp>=0 then 1.0*count(*) end as win_run_len_decimal, 
    case when sp<=0 then 1.0*count(*) end as loss_run_len_decimal 
    from Trk 
    group by symbol_id, sp, rk-rksp 
) 
    select 
    symbol_id, 
    avg(win_run_len_decimal) as avg_winning_streak, 
    max(win_run_len_decimal) as longest_winning_streak, 
    avg(loss_run_len_decimal) as avg_losing_streak, 
    max(loss_run_len_decimal) as longest_losing_streak 
    from Trk_agg 
    group by symbol_id; 
+0

solution brillante en utilisant la fonction de rang et CTE, en particulier l'agrégation. –

+0

Comment pourriez-vous modifier cela pour retourner les lignes de données qui sont dans la meilleure séquence? Dois-je faire une nouvelle question à ce sujet? – bladefist

Questions connexes