3

SQLite (開発) および MySQL (本番) から Postgres への移植を含め、自分の VPS から Heroku に移行しようとしている Ruby on Rails 2.3.x アプリケーションがあります。

これは、私が使用している典型的な Rails 呼び出しです。

spots = Spot.paginate(:all, :include => [:thing, :user, :store, {:thing => :tags}, {:thing => :brand}], :group => :thing_id, :order => order, :conditions => conditions, :page => page, :per_page => per_page)

質問 1:のようなエラーがたくさん発生しPG::Error: ERROR: column "spots.id" must appear in the GROUP BY clause or be used in an aggregate functionます。ここでは、SQLite/MySQL の方が明らかに寛容でした。もちろん、指定したフィールドを:groupパラメーターに追加することでこれらを簡単に修正できますが、コードを台無しにしているように感じます。より良い方法はありますか?

質問 2: Postgres にないすべての GROUP BY 列を投入すると、次のステートメントになります (:group変更されているだけです)。

spots = Spot.paginate(:all, :include => [:thing, :user, :store, {:thing => :tags}, {:thing => :brand}], :group => 'thing_id,things.id,users.id,spots.id', :order => order, :conditions => conditions, :page => page, :per_page => per_page)

これにより、次の SQL コードが生成されます。

SELECT * FROM (SELECT DISTINCT ON ("spots".id) "spots".id, spots.created_at AS alias_0 FROM "spots"  
LEFT OUTER JOIN "things" ON "things".id = "spots".thing_id 
WHERE (spots.recommended_to_user_id = 1 OR spots.user_id IN (1) OR things.is_featured = 't')  
GROUP BY thing_id,things.id,users.id,spots.id) AS id_list 
ORDER BY id_list.alias_0 DESC LIMIT 16 OFFSET 0;

...エラーが発生しますPG::Error: ERROR: missing FROM-clause entry for table "users"。どうすればこれを解決できますか?

4

2 に答える 2

4

質問1:

...もっと良い方法はありますか?

はい。GROUP BYPostgreSQL 9.1以降、テーブルの主キーは、句内のテーブルのすべての列を論理的にカバーします。バージョン9.1のリリースノートを引用します。

主キーがGROUPBY句で指定されている場合に、クエリターゲットリストで非GROUP BY列を許可する(Peter Eisentraut)

質問2:

次のステートメント...はエラーを生成します

PG ::エラー:エラー:テーブル「users」のFROM句エントリがありません

どうすればこれを解決できますか?

まず(いつものように!)、理解しやすいようにクエリをフォーマットしました。犯人は大胆に強調しています:

SELECT *
FROM  (
   SELECT DISTINCT ON (spots.id)
          spots.id, spots.created_at AS alias_0
   FROM   spots  
   LEFT   JOIN things ON things.id = spots.thing_id 
   WHERE (spots.recommended_to_user_id = 1 OR
          spots.user_id IN (1) OR
          things.is_featured = 't')  
   GROUP  BY thing_id, things.id, users.id, spots.id
   ) id_list 
ORDER  BY id_list.alias_0 DESC
LIMIT  16
OFFSET 0;

今は明らかですよね?
まあ、それのすべてではありません。もっとたくさんあります。DISTINCT ONそしてGROUP BY、同じクエリで、その用途はありますが、ここではありません。根本的に単純化して:

SELECT s.id, s.created_at AS alias_0
FROM   spots s
WHERE  s.recommended_to_user_id = 1 OR
       s.user_id = 1 OR
       EXISTS (
          SELECT 1 FROM things t
          WHERE  t.id = s.thing_id
          AND    t.is_featured = 't')
ORDER  BY s.created_at DESC
LIMIT  16;

EXISTS半結合は、後でGROUP BYアプリオリに必要になることを回避します。これは(正しいことに加えて)はるかに高速であるはずです-欠落しているテーブル定義に関する私の仮定が成り立つ場合。

于 2012-11-10T04:28:30.757 に答える
0

「純粋な SQL」ルートに行くと、ワームの缶が開いたので、代わりに will_paginate gem を保持し、Spot.paginateパラメーターを微調整してみました。:joinsパラメータは非常に役立つことが判明しました。

これは現在私のために働いています:

spots = Spot.paginate(:all, :include => [:thing, {:thing => :tags}, {:thing => :brand}], :joins => [:user, :store, :thing], :group => 'thing_id,things.id,users.id,spots.id', :order => order, :conditions => conditions, :page => page, :per_page => per_page)
于 2013-01-02T15:33:56.297 に答える