2012-04-15 31 views
27

Tôi tìm thấy một số chủ đề ở đây trên SO, nhưng tôi vẫn không thể tìm thấy các thiết lập quyền cho truy vấn của tôi.PostgreSQL - GROUP BY khoản hoặc được sử dụng trong một chức năng tổng hợp

Đây là truy vấn, rằng tôi hoạt động tốt trên 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') 

Nhưng trên Heroku mang lại cho tôi những lỗi ở trên - mệnh đề GROUP BY hoặc được sử dụng trong một chức năng tổng hợp.

Sau đó, tôi đã đọc ở đâu đó, rằng tôi nên xác định tất cả các cột trong bảng, vì vậy tôi cố gắng này:

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

Nhưng điều này không hoạt động trên localhost và cũng không phải trên Heroku ...

Cấu hình đúng của truy vấn là gì?

Trả lời

26

Tôi nghĩ bạn đang cố tổng hợp và nhóm theo cùng một cột. Nó phụ thuộc vào dữ liệu bạn muốn. Ether làm điều này:

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 

Hoặc bạn muốn đếm tất cả có thể? Sau đó, như sau:

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

Cảm ơn điều đó thực sự giúp làm cho hoạt động này rõ ràng. – edencorbin

5

Bạn có thể sử dụng mẹo MAX() trên cột ô tô.

@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

Bất kỳ ý tưởng nào nếu sử dụng tối đa như vậy có thể gây ra vấn đề về hiệu suất? – achabacha322

30

Một truy vấn như thế này (lấy tất cả hoặc hầu hết hàng) là nhanh nếu bạn GROUP trước khi bạn JOIN. Như thế này:

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; 

Bằng cách này bạn cần ít hoạt động tham gia hơn. Và các hàng của bảng cars không cần phải được nhân trước bằng cách tham gia nhiều người dùng và sau đó được nhóm lại thành duy nhất một lần nữa.
Chỉ có bảng bên phải phải được nhóm lại, điều này làm cho logic đơn giản hơn.

Các vấn đề liên quan