2012-04-15 11 views
27

Ho trovato alcuni argomenti qui su SO, ma non riesco ancora a trovare l'impostazione corretta per la mia query.PostgreSQL - clausola GROUP BY o essere utilizzato in una funzione di aggregazione

Si tratta di interrogazione, che mi funziona bene su localhost:

@cars = Car.find_by_sql('SELECT cars.*, COUNT(cars.id) AS counter 
         FROM cars 
         LEFT JOIN users ON cars.id=users.car_id 
         GROUP BY cars.id ORDER BY counter DESC') 

Ma Heroku mi dà l'errore di cui sopra - clausola GROUP BY o essere utilizzati in una funzione di aggregazione.

Poi ho letto da qualche parte, che avrei dovuto specificare tutte le colonne della tabella, così ho provato questo:

@cars = Car.find_by_sql('SELECT cars.id, cars.name, cars.created_at, 
           cars.updated_at, COUNT(cars.id) AS counter 
         FROM cars 
         LEFT JOIN users ON cars.id=users.car_id 
         GROUP BY (cars.id, cars.name, cars.created_at, cars.updated_at) 
         ORDER BY counter DESC') 

Ma questo non funziona su localhost e anche non su Heroku ...

Quale dovrebbe essere la giusta configurazione della query?

risposta

26

Penso che si stia cercando di aggregare e raggruppare sulla stessa colonna. Dipende dai dati che vuoi. Ether fai questo:

SELECT 
cars.name, 
cars.created_at, 
cars.updated_at, 
COUNT(cars.id) AS counter 
FROM cars 
LEFT JOIN users 
    ON cars.id=users.car_id 
GROUP BY cars.name, cars.created_at, cars.updated_at 
ORDER BY counter DESC 

Oppure vuoi contare tutto forse? Quindi in questo modo:

SELECT 
cars.id, 
cars.name, 
cars.created_at, 
cars.updated_at, 
COUNT(*) AS counter 
FROM cars 
LEFT JOIN users 
    ON cars.id=users.car_id 
GROUP BY cars.id, cars.name, cars.created_at, cars.updated_at 
ORDER BY counter DESC 
+0

Grazie davvero per rendere chiara questa operazione. – edencorbin

5

È possibile utilizzare MAX() trucco su colonna di vetture.

@cars = Car.find_by_sql(' 
SELECT cars.id, MAX(cars.name) as name, MAX(cars.created_at) AS 
created_at, MAX(cars.updated_at) as updated_at, COUNT(cars.id) AS counter 
FROM cars LEFT JOIN users ON cars.id=users.car_id 
GROUP BY cars.id ORDER BY counter DESC') 
+0

Qualche idea se l'uso di max come questo può causare problemi di prestazioni? – achabacha322

30

Una query come questo (il recupero di tutti o la maggior parte dei file) è più veloce se GROUP prima JOIN. In questo modo:

SELECT id, name, created_at, updated_at, u.ct 
FROM cars c 
LEFT JOIN (
    SELECT car_id, count(*) AS ct 
    FROM users 
    GROUP BY 1 
    ) u ON u.car_id = c.id 
ORDER BY u.ct DESC; 

In questo modo sono necessarie molte meno operazioni di join. E le righe della tabella cars non devono essere prima moltiplicate unendole a più utenti ciascuna e quindi raggruppate per essere nuovamente uniche.
Solo la tabella di destra deve essere raggruppata, il che rende anche la logica più semplice.

Problemi correlati