2009-05-14 9 views
1

J'ai une table avec les colonnes suivantes:Interrogation pour lignes consécutives avec certaines caractéristiques

id int(10) 
user int(10) 
winner int(10) 
profit double 
created datetime 

La colonne gagnant peut être 0 ou 1. Je voudrais créer une requête qui retourne le maximum nombre de gagnants consécutifs tel que commandé par la colonne datetime créée avec la première et dernière date créée ainsi que la somme de la colonne de profit de cette période de gagnants consécutifs.

+0

Êtes-vous à la recherche de gagnants consécutifs avec le même utilisateur? Ou juste des victoires consécutives? – Andomar

+0

L'un ou l'autre, mais j'espère que la solution peut implémenter l'un ou l'autre. – Dave

Répondre

0

Voici une solution possible qui examine les séquences gagnantes par ID utilisateur.

select head.userid, head.id, sum(profit), count(*) 
from #bingo b 
inner join (
    select cur.userid, cur.id 
    from #bingo cur 
    left join #bingo prev 
     on cur.userid = prev.userid 
     and prev.id < cur.id 
     and not exists(
      select * 
      from #bingo inbetween 
      where prev.userid = inbetween.userid 
      and prev.id < inbetween.id 
      and inbetween.id < cur.id) 
    where cur.winner = 1 
    and IsNull(prev.winner,0) = 0 
) head 
    on head.userid = b.userid 
    and head.id <= b.id 
 
left join (
    select cur.userid, cur.id 
    from #bingo cur 
    left join #bingo prev 
     on cur.userid = prev.userid 
     and prev.id < cur.id 
     and not exists(
      select * 
      from #bingo inbetween 
      where prev.userid = inbetween.userid 
      and prev.id < inbetween.id 
      and inbetween.id < cur.id) 
    where cur.winner = 1 
    and IsNull(prev.winner,0) = 0 
) nexthead 
    on nexthead.userid = b.userid 
    and head.id < nexthead.id 
    and nexthead.id <= b.id 
where nexthead.id is null 
and b.winner = 1 
group by head.userid, head.id 

Les deux « têtes » sont identiques sous-requêtes, vous pouvez les mettre dans une vue ou WITH où ceux-ci sont pris en charge. La sous-requête "heads" recherche chaque tête d'une série de victoires; c'est-à-dire, la première victoire ou une victoire qui est précédée d'une perte. Je suppose que votre identifiant augmente au fil du temps, donc je n'utilise pas la colonne Créé.

La requête ci-dessous qui recherche la tête correspondante pour chaque ligne. L'identifiant d'une tête doit être plus petit ou égal à l'identifiant de la ligne en cours, et il ne doit pas y avoir d'autre tête entre les deux. Ensuite, c'est une simple question de regroupement sur la tête, de sommation des profits et de comptage des rangées.

+0

Je vois ce que vous obtenez, mais j'utilise mysql et ça n'aime pas l'instruction with: ERREUR 1064 (42000): Vous avez une erreur dans votre syntaxe SQL; Vérifiez le manuel qui correspond à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de '' – Dave

+0

réécrit sans WITH maintenant.Pour performance, vérifiez si vous avez une clé primaire sur l'ID, et un index sur l'ID utilisateur – Andomar

+0

'IsNull (prev.winner, 0) = 0' ne fonctionne pas de cette façon dans mySQL Il pourrait être réécrit à mySQL comme 'IsNull (prev.winner) = 1' à la place –

0

Je ne l'ai pas testé mais peut-être que cela fonctionnera.

select first_winner.created, last_winner.created, sum(mid_winner.profit) 
      from T first_winner 
    join T last_winner 
      on first_winner.created <= last_winner.created 
      and first_winner.winner = 1 
      and last_winner.winner = 1 
      and not exists -- no losers in between first_winner and last_winner 
      (
      select * from T loser 
      where loser.winner = 0 
      and first_winner.created <= loser.created 
            and loser.created <= last_winner.created 
     ) 
    join T mid_winner 
      on first_winner.created <= mid_winner.created 
           and mid_winner.created <= last_winner.created 
      and mid_winner.winner = 1 
    left join T bef_first_winner -- winner before first winner with no losers in between 
      on bef_first_winner.winner = 1 
      and bef_first_winner.created < first_winner.created 
      and not exists 
      ( 
      select * from T b_loser 
      where b_loser.winner = 0 
      and bef_first_winner.created <= b_loser.created 
       and b_loser.created <= first_winner.created 
     ) 
    left join T after_last_winner -- winner after last winner with no losers in between 
      on after_last_winner.winner = 1 
      and last_winner.created < after_last_winner.created 
      and not exists 
      ( 
      select * from T a_loser 
      where a_loser.winner = 0 
      and last_winner.created <= a_loser.created 
       and a_loser.created <= after_last_winner.created 
     ) 
    where bef_first_winner.id is null 
     and after_last_winner.id is null 
    group by first_winner.created, last_winner.created 
+0

Je reçois: "ERREUR 1140 (42000): Le mélange des colonnes GROUP (MIN(), MAX(), COUNT(), ...) sans colonnes GROUP est illégal s'il n'y a pas de clause GROUP BY" – Dave

+0

désolé, je J'ai oublié la clause de groupe –

+0

Je l'ai exécuté et il fonctionne toujours. Été quelques heures maintenant. ;-) – Dave

Questions connexes