2015-12-16 10 views
5

Il mio obiettivo è generare un rapporto che mostri l'occupazione media di un garage (asse y) in un dato giorno della settimana e/o ora del giorno. Il mio modello di dati è la seguente:Segnalazione su una media raggruppata su un gruppo di record

  • Garage has_many Auto e Garage has_many Appuntamenti, through: :cars
  • auto has_many Appuntamenti
  • appuntamento ha settori quali:
    • picked_up_at (datetime)
    • returned_at (datetime)

Inoltre, Garage ha un campo capacity (integer), che è il numero massimo di automobili che si adatterà al garage.

Se ho un elenco di appuntamenti negli ultimi 6 mesi e vorrei generare un grafico a linee con l'asse x che mostra ogni giorno della settimana, suddiviso in intervalli di 4 ore, e il -axis che mostra la percentuale media di occupazione (numero di auto nel garage/capacità) nel periodo di 6 mesi per l'intervallo di giorni/ore specificato, come posso raccogliere i dati da riportare?

E.g. un'automobile è In dal momento del ritorno di un appuntamento fino al prossimo ritiro dell'appuntamento, e Out dal ritiro dell'appuntamento fino al momento in cui è returned_at.

Ho molti problemi a rendere la connessione da questi punti dati al modo migliore per generare report significativi e presentarli all'utente finale.

Sto utilizzando Rails 4.1 e Ruby 2.0.

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

+0

vostro violino è per MySQL. Dovrai cambiarlo in Postgres in modo che corrisponda alla tua domanda: http://sqlfiddle.com/#!15/77901/1. Inoltre, hai trascurato di menzionare possibili valori NULL in 'returned_at' (ho adattato anche lo schema per abbinare i nomi delle tue colonne). –

+0

Quindi hai la tua risposta? –

+0

@ErwinBrandstetter - scusate per il ritardo nella selezione di una risposta, sono stato fuori dal paese, ma lavorerò per implementare la vostra soluzione e, non appena lo farò, accetterò la risposta. Grazie ancora – jackerman09

risposta

4

Questa query fare tutto (adattato per il vostro violino aggiunto):

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.

Se returned_at IS NULL, questa query presuppone che l'auto è ancora in uso. Quindi NULL non dovrebbe verificarsi per altri casi o si ha un errore nel calcolo.

Per prima cosa, creo le serie temporali con la comoda funzione generate_series().

Quindi partecipare agli appuntamenti in cui il timestamp rientra in una prenotazione.
Assumo ogni appuntamento includendo il timestamp superiore ed inferiore in quanto convenzione diffusa.

Aggregare e contare prima di unire ai garage (più veloce in questo modo). Confronto:

calcoli per cento nel esterna SELECT.
I moltiplicare il numero bigint con numeric (o facoltativamente real o float) per conservare cifre frazionarie, che verrebbero tagliate in una divisione intera. Poi giro a due cifre frazionarie.

Nota che questa non è esattamente la percentuale media di ogni periodo di 4 ore, ma solo la percentuale corrente in ciascun punto nel tempo, che è un'approssimazione della media reale. Potresti iniziare con un timestamp dispari come "2015-06-01 01:17", in modo da non cadere tra le prenotazioni che verrebbero probabilmente invertite a ore o qualcosa del genere, il che potrebbe aumentare l'errore medio dell'approssimazione.

È possibile eseguire un calcolo esatto anche per periodi di 4 ore, ma è più sofisticato. Una tecnica semplice sarebbe quella di ridurre l'intervallo a 10 minuti o una granularità sufficientemente dettagliata per catturare l'immagine completa.

correlate (con un esempio per il calcolo esatto):

+0

Grazie per la risposta rapida e dettagliata! Esaminerò/testò questo e riferirei! – jackerman09

+0

Quando copio la query nel mio fiddle, viene visualizzato questo errore: "Si è verificato un errore nella sintassi SQL; controlla il manuale che corrisponde alla versione del tuo server MySQL per la sintassi corretta da usare vicino a 'numerico' 100 ')/g.capacity, 2) AS PCT FROM (SELECT ts, c.garage_id, count (' alla riga 1', dovrebbe che ha funzionato direttamente come l'avevi scritto? – jackerman09

+0

@ jackerman09: Perché * il tuo * fiddle è per MySQL (che è semplicemente sbagliato per una domanda taggata per Postgres.) Prova * my * fiddle, funziona –

Problemi correlati