2015-12-16 10 views
5

Mein Ziel ist es, einen Bericht zu erstellen, der die durchschnittliche Belegung einer Garage (Y-Achse) zu einem bestimmten Wochentag und/oder einer bestimmten Uhrzeit anzeigt. Meine Datenmodell ist wie folgt:Bericht über einen gruppierten Durchschnitt über eine Gruppe von Datensätzen

  • Garage has_many Autos und Garage has_many Termine, through: :cars
  • Auto has_many Termine
  • Termin hat Felder wie:
    • picked_up_at (Datumzeit)
    • returned_at (DatumZeit)

Auch Garage hat ein Feld capacity (integer), das ist die maximale Anzahl von Autos, die in die Garage passen.

Wenn ich eine Liste von Terminen in den letzten 6 Monaten habe, und ich möchte ein Liniendiagramm mit der X-Achse jeden Wochentag, in 4-Stunden-Intervallen, und die y -Achse zeigt die durchschnittliche prozentuale Belegung (Anzahl der Autos in der Garage/Kapazität) über den 6-Monats-Zeitraum für den angegebenen Tag/Stunde-Intervall an, wie kann ich diese Daten sammeln, um darüber zu berichten?

z. ein Auto ist In von der Zeit der Rückkehr eines Termins bis zur Abholung des nächsten Termins und Out von der Abholung des Termins, bis es returned_at Zeit ist.

Ich habe eine Menge Probleme, die Verbindung von diesen Datenpunkten zum besten Weg, um sinnvoll zu berichten und präsentieren sie an den Endnutzer.

Ich verwende Rails 4.1 und Ruby 2.0.

Edit: SQL Fiddle - http://sqlfiddle.com/#!9/a72fe/1

+0

Ihre Geige ist für MySQL. Sie sollten dies in Postgres ändern, damit es zu Ihrer Frage passt: http://sqlfiddle.com/#!15/77901/1. Außerdem haben Sie es versäumt, mögliche NULL-Werte in 'returned_at' zu erwähnen (ich habe das Schema auch an Ihre Spaltennamen angepasst.) –

+0

Also haben Sie Ihre Antwort? –

+0

@ErwinBrandstetter - Entschuldigung für die Verzögerung bei der Auswahl einer Antwort, ich war außer Landes, aber ich werde arbeiten, um Ihre Lösung zu implementieren, und sobald ich das tue, werde ich die Antwort akzeptieren. Danke nochmal – jackerman09

Antwort

4

Diese Abfrage alles (zu Ihrer zusätzlichen Geige angepasst) tun würde:

SELECT a.ts, g.*, round((a.ct * numeric '100')/g.capacity, 2) AS pct 
FROM (
    SELECT ts, c.garage_id, count(*) AS ct 
    FROM generate_series(timestamp '2015-06-01 00:00' -- lower and 
         , timestamp '2015-12-01 00:00' -- upper bound of range 
         , interval '4h') ts 
    JOIN appointment a ON a.picked_up_at <= ts  -- incl. lower 
         AND (a.returned_at > ts OR 
          a.returned_at IS NULL) -- excl. upper bound 
    JOIN car c ON c.id = a.car_id 
    GROUP BY 1, 2 
    ) a 
JOIN garage g ON g.id = a.garage_id 
ORDER BY 1, 2; 

SQL Fiddle.

Wenn returned_at IS NULL nimmt diese Abfrage, dass das Auto ist noch in Verwendung. Daher sollte NULL für andere Fälle nicht auftreten oder Sie haben einen Fehler in der Berechnung.

Zuerst baue ich die Zeitreihe mit der bequemen generate_series() Funktion.

Dann zu Terminen, wo der Zeitstempel in eine Buchung fällt.
Ich nehme jeden Termin mit einschließlich niedriger und exklusive oberen Zeitstempel als es die weit verbreitete Konvention.

Aggregieren und zählen, bevor wir zu Garagen kommen (schneller auf diese Weise). Vergleichen:

Prozent Berechnungen in der äußeren SELECT.
Ich multipliziere die bigint Nummer mit numeric (oder optional real oder float), um Bruchzahlen zu erhalten, die in einer ganzzahligen Division abgeschnitten würden. Dann runde ich auf zwei Nachkommastellen.

Hinweis, dass dies nicht genau der durchschnittliche Prozentsatz jeder 4-Stunden-Periode ist, sondern nur der aktuelle Prozentsatz zu jedem Zeitpunkt, was eine Annäherung an den wahren Durchschnitt ist. Sie könnten mit einem ungeraden Zeitstempel wie '2015-06-01 01:17' beginnen, um nicht zwischen Buchungen zu verfallen, die wahrscheinlich zu vollen Stunden umkehren würden oder etwas, was den mittleren Fehler der Annäherung erhöhen könnte.

Sie können auch eine exakte Berechnung für 4h Perioden durchführen, aber das ist anspruchsvoller. Eine einfache Technik wäre die Reduzierung des Intervalls auf 10 Minuten oder eine Granularität, die detailliert genug ist, um das Gesamtbild zu erfassen.

Verwandte (mit einem Beispiel für die exakte Berechnung):

+0

Danke für die schnelle und ausführliche Antwort! Ich werde es überprüfen/testen und darüber berichten! – jackerman09

+0

Wenn ich Ihre Abfrage in meine Geige kopiere, bekomme ich diesen Fehler: 'Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, um die richtige Syntax in der Nähe von 'numeric' 100 ')/g.capacity, 2) AS pct FROM (SELECT ts, c.garage_id, count (' bei Zeile 1 ', sollte das hat direkt funktioniert, wie du es geschrieben hattest? – jackerman09

+0

@ jackerman09: Weil * deine * Geige für MySQL ist (was einfach falsch ist für eine Frage, die für Postgres getaggt ist) Versuch * meine * Geige, es funktioniert –

Verwandte Themen