2012-04-15 12 views
27

Znalazłem kilka tematów na SO, ale nadal nie mogę znaleźć odpowiedniego ustawienia dla mojego zapytania.PostgreSQL - klauzula GROUP BY lub może być używana w funkcji agregującej

To jest kwerenda, że ​​mnie dobrze działa na 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') 

Ale Heroku daje mi błąd powyżej - klauzuli GROUP BY lub być wykorzystane w łącznej funkcji.

Potem przeczytałem gdzieś, że należy określić wszystkie kolumny w tabeli, więc próbowałem to:

@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') 

Ale to nie działa na localhost, a także nie na Heroku ...

Jaka powinna być właściwa konfiguracja zapytania?

Odpowiedz

26

Myślę, że próbujesz agregować i grupować według tej samej kolumny. To zależy od danych, które chcesz. Eter to:

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 

A może chcesz liczyć wszystkie? Następnie tak:

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

Dzięki, że naprawdę pomóc w tej operacji jasne. – edencorbin

5

Można użyć MAX() trik na kolumnie samochodów.

@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

Każdy pomysł, jeśli używasz takiego maxa, może powodować problemy z wydajnością? – achabacha322

30

Zapytanie takie jak to (pobieranie wszystkich lub większości wierszy) jest szybciej jeśli GROUP przed JOIN. W ten sposób:

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; 

W ten sposób potrzebujesz znacznie mniej operacji łączenia. A wiersze tabeli cars nie muszą być najpierw mnożone przez dołączanie do wielu użytkowników, a następnie grupowanie z powrotem, aby znów były niepowtarzalne.
Tylko prawa tabela musi być zgrupowana, co czyni logikę prostszą.

Powiązane problemy