web-dev-qa-db-ja.com

PostgreSQL-GROUP BY句に表示するか、集約関数で使用する必要があります

私はこのエラーをpgプロダクションモードで取得していますが、sqlite3開発モードでは問題なく動作します。

 ActiveRecord::StatementInvalid in ManagementController#index

PG::Error: ERROR:  column "estates.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "estates".* FROM "estates"  WHERE "estates"."Mgmt" = ...
               ^
: SELECT "estates".* FROM "estates"  WHERE "estates"."Mgmt" = 'Mazzey' GROUP BY user_id

@myestate = Estate.where(:Mgmt => current_user.Company).group(:user_id).all
26
@myestate1 = Estate.where(:Mgmt => current_user.Company)
@myestate = @myestate1.select("DISTINCT(user_id)")

これは私がやったことです。

3

user_idPRIMARY KEYの場合、PostgreSQLをアップグレードする必要があります。新しいバージョンでは、主キーによるグループ化が正しく処理されます。

user_idが一意でもない場合nor問題の 'estates'関係の主キーは、このクエリはあまり意味がありません。 PostgreSQLには、複数の行が同じuser_idを共有するestatesの各列に対して返す値whichを知る方法がありません。 minmaxavgstring_aggarray_aggなど、必要なものを表す集約関数を使用するか、列を追加する必要があります。 )GROUP BYに関心があります。

あるいは、本当に任意の行を選択する必要がある場合は、DISTINCT ONORDER BYを使用するようにクエリを言い換えることができますが、ActiveRecordを使用してそれを表現することはできません。

SQLiteやMySQLなどの一部のデータベースは、任意の行を選択するだけです。これはPostgreSQLチームによって不正確で安全でないと見なされているため、PostgreSQLはSQL標準に従っており、そのようなクエリはエラーであると見なします。

あなたが持っている場合:

col1    col2
fred    42
bob     9
fred    44
fred    99

そしてあなたはする:

SELECT col1, col2 FROM mytable GROUP BY col1;

行を取得する必要があることは明らかです。

bob     9

しかし、fredの結果はどうですか?選択する正しい答えは1つもないため、データベースはこのような安全でないクエリの実行を拒否します。任意のcol2に対してgreatestcol1が必要な場合は、max集計を使用します。

SELECT col1, max(col2) AS max_col2 FROM mytable GROUP BY col1;
43
Craig Ringer

私は最近、MySQLからPostgreSQLに移行し、同じ問題に遭遇しました。参考までに、私が見つけた最良のアプローチは、このSO answer:

for Ruby on Rails/ActiveRecord によるエレガントなPostgreSQLグループ

これにより、選択した列の一意の値ごとに、他のクエリ条件と一致する1つのレコードを取得できます。

MyModel.where(:some_col => value).select("DISTINCT ON (unique_col) *") 

行内の他のすべての列値を取得できるため、DISTINCT ONを選択します。 DISTINCTのみでは、その特定の列の値のみが返されます。

15
Jin Hian Lee

自分でエラーを頻繁に受け取った後、Rails(私はRails 4)を使用しています)がグループ化クエリの最後に 'order by id'を自動的に追加することに気付きましたこれにより、上記のエラーが発生することがよくあります。したがって、Railsクエリの最後に独自の.order(:group_by_column)を追加してください。したがって、次のようになります。

@problems = Problem.select('problems.username, sum(problems.weight) as weight_sum').group('problems.username').order('problems.username')
6
hec