2009-05-14 5 views
1

ich eine Tabelle mit den folgenden Spalten haben:Abfragen für aufeinander folgende Zeilen mit bestimmten Eigenschaften

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

Der Gewinner Spalte kann entweder 0 oder 1 sein Ich mag würde eine Abfrage erstellen, die die maximale zurückgibt Anzahl der aufeinander folgenden Gewinner, wie von der erstellten Datum/Zeit-Spalte bestellt, zusammen mit dem ersten und letzten Erstellungsdatum sowie der Summe der Gewinnspalte aus dieser Periode der aufeinander folgenden Gewinner.

+0

Suchen Sie nach aufeinanderfolgenden Gewinnern mit demselben Benutzer? Oder nur aufeinander folgende Siege? – Andomar

+0

Entweder man, aber hoffentlich kann die Lösung beide implementieren. – Dave

Antwort

0

Hier ist eine mögliche Lösung, die Gewinnsträhne pro Benutzerid betrachtet.

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 

Die beiden „Köpfe“ Unterabfragen sind identisch, können Sie sie in einer Ansicht oder ein MIT, wo diejenigen unterstützt werden, setzen könnte. Die "Kopf" -Unterabfrage sucht nach jedem Kopf einer Gewinnserie; das ist der erste Sieg oder ein Sieg, dem ein Verlust vorausgeht. Ich gehe davon aus, dass Ihre ID im Laufe der Zeit zunimmt. Daher verwende ich nicht die Spalte "Erstellt".

Die folgende Abfrage durchsucht den entsprechenden Kopf für jede Zeile. Die ID eines Kopfes muss kleiner oder gleich der ID der aktuellen Zeile sein, und es darf keinen anderen Kopf dazwischen geben.

Danach ist es eine einfache Sache der Gruppierung auf dem Kopf, und summiert die Gewinne und das Zählen der Zeilen.

+0

Ich sehe, was Sie bekommen, aber ich benutze mysql und es mag nicht die with-Anweisung: Fehler 1064 (42000): Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version für die richtige Syntax in der Nähe 'mit Köpfen als ( – Dave

+0

Umgeschrieben ohne WITH jetzt. Für die Leistung, überprüfen Sie, ob Sie einen Primärschlüssel auf ID und einen Index auf Benutzer-ID – Andomar

+0

'IsNull (prev.winner, 0) = 0' funktioniert in mySQL nicht so, sondern könnte stattdessen als 'IsNull (prev.winner) = 1' in mySQL geschrieben werden. –

0

Ich habe es nicht getestet, aber vielleicht wird das funktionieren.

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

Ich bekomme: "Fehler 1140 (42000): Mischen von GROUP Spalten (MIN(), MAX(), COUNT(), ...) ohne GROUP Spalten ist illegal, wenn es keine GROUP BY-Klausel" – Dave

+0

Sorry, ich habe die Gruppenklausel vergessen –

+0

Ich habe es ausgeführt und es läuft noch. Schon ein paar Stunden. ;-) – Dave

Verwandte Themen