2016-06-27 14 views
2

Ich habe versucht, meinen Kopf um die richtigen Schienen zu wickeln, um dies zu tun. Ich habe zwei Tische, einer ist Spieler, der eine Beziehung von Tag zu Tag hat. Jeden Tag werden neue Statistiken aufgezeichnet. Ich versuche, die Top-Statistik nur für diesen Monat zu erhalten, aber die Statistiken werden insgesamt aufgezeichnet. Die heutigen Statistiken sind die Summe aller Monate. Also muss ich den aktuellen Monat nehmen und ihn vom letzten Tag des vorherigen Monats abziehen.Aktiver Datensatz Subtrahieren Zwei Werte mit unterschiedlichen where-Anweisungen?

Ich verwende Folgendes, um die Top-Stat für den aktuellen Tag zu erhalten.

Also wie würde ich es für Top-Spieler aus dem Unterschied dieses Monats tun - letzten Monat? Ich würde annehmen, dass es in etwa so aussehen würde,

@gamesplayed = (Player.joins(:dailystats).select('players.*, dailystats.gamesplayed AS average_score').where('(MONTH(statdate) = MONTH(NOW()))') - Player.joins(:dailystats).select('players.*, dailystats.gamesplayed AS average_score').where('(MONTH(statdate) = MONTH(NOW() - INTERVAL 1 MONTH)')).first.name 
+0

Ihre Lösung funktioniert nicht oder Sie fragen nach einer besseren Lösung? Für letzteres wird es durch die Änderung der Speicherungsart der Daten zu einer optimierten Einzelabfrage kommen. Wenn Sie die inkrementelle Änderung speichern, anstatt sie zu akkumulieren, wird das Abrufen erleichtert. – Leito

Antwort

2

Sie zwei Abfragen ausführen können, wie Ihre vorgeschlagene Lösung hat, aber der - Betreiber ist auf jeden Fall nicht intelligent genug, die reihenweise Differenz jedes einzelnen von ihnen zu behandeln Rechen . Sie müssten Ihren eigenen Code schreiben, um jede Zeile "diesen Monat" zu durchlaufen, die entsprechende Zeile "letzten Monat" zu finden und die Differenz zu speichern.

Aber Sie können dies auch in einer Abfrage tun. Es wird kompliziert, dies in der Abfragesyntax von Rails zu tun, da wir uns hier relativ fortgeschrittenen SQL nähern, aber ich werde mein Bestes geben.

Player 
    .joins("JOIN (SELECT player_id, 
      SUM(gamesplayed) as gamesplayed, COUNT(*) as count 
      FROM dailystats 
      WHERE DATE_TRUNC('MONTH', statdate) = DATE_TRUNC('MONTH', NOW()) 
      GROUP BY player_id) this_month 
      ON this_month.player_id = players.id 
     ") 
    .joins("JOIN (SELECT player_id, 
      SUM(gamesplayed) as gamesplayed, COUNT(*) as count 
      FROM dailystats 
      WHERE DATE_TRUNC('MONTH', statdate) = 
       DATE_TRUNC('MONTH', NOW() - INTERVAL '1 month') 
      GROUP BY player_id) last_month 
      ON last_month.player_id = players.id 
     ") 
    .select('players.*') 
    .select('this_month.gamesplayed - last_month.gamesplayed AS gamesplayed_change') 

(Sie können feststellen, ich Ihre MONTH() Nutzung DATE_TRUNC('month') geändert; der Grund für diesen Monat ist, wird 1 zurückkehren, 2, 3, 4 usw., was bedeutet, wenn Ihre Website für länger als ein Jahr läuft man Ich werde damit beginnen, die Daten des letzten Jahres unangemessen zurückgemischt zu bekommen.)

Die obige Vorgehensweise funktioniert, indem Sie zweimal auf die dailystats-Tabelle zugreifen. einmal für Statistiken in diesem Monat und einmal für Statistiken im letzten Monat. Da es jedoch für jeden Spieler mehrere Einträge für Tagesstatistiken gibt, gruppieren wir zuerst die Statistiken jedes Monats über eine Unterabfrage, so dass wir erwarten, dass nur eine dieser Reihen mit jedem Spieler verbunden wird. Dann kann unsere SELECT-Klausel die monatlichen Statistiken verwenden, die wir oben berechnet haben, um einen vernünftigen Unterschied zu erhalten.

Jetzt ist dieser Code zu lang, um einfach in Ihre Codebasis zu fallen. Um es zu bereinigen, möchten Sie vielleicht eine monatliche Statistik-Roll-up-Tabelle erstellen (die als Ansicht in Ihrer Datenbank implementiert werden könnte) oder Ihren Code in Raw-SQL konvertieren (extrahiert in ein separates Modul).

P.S. Der obige Code wurde nicht getestet und enthält daher wahrscheinlich einen oder zwei Bugs. Bitte Kommentar, wenn es nicht funktioniert und ich werde helfen, zu lösen.

Verwandte Themen