web-dev-qa-db-ja.com

PostgreSQL-GROUP BY句、または集約関数で使用される

SOでいくつかのトピックを見つけましたが、クエリに適した設定がまだ見つかりません。

これはクエリであり、ローカルホストでうまく機能します:

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

しかし、Herokuでは上記のエラーが表示されます-GROUP BY句または集計関数で使用される

次に、テーブルのすべての列を指定する必要があることをどこかで読んだので、これを試しました:

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

しかし、これはローカルホストでは機能せず、Herokuでも機能しません...

クエリの正しい構成は何ですか?

29
user984621

同じ列で集計およびグループ化しようとしていると思います。必要なデータによって異なります。エーテルはこれを行います:

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

または多分すべてを数えたいですか?次に、このように:

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
28
Arion

このような(すべてまたはほとんどの行を取得する)クエリは、GROUPの前にJOINを指定するとfasterになります。このような:

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;

これにより、必要な結合操作がはるかに少なくなります。そして、テーブルの行carsは、最初に多くのユーザーにそれぞれ参加することによって乗算され、その後再び一意になるようにグループ化される必要はありません。
正しいテーブルのみをグループ化する必要があります。これにより、ロジックも簡単になります。

31

車の列でMAX()トリックを使用できます。

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