2012-04-13 15 views
2

author_idフィールドを持つブックテーブルがあります。ユニークフィールド値でグループ化された最新の行を取得します

すべての著者の書籍が1つだけ含まれている書籍の配列を取得したいと思います。最新のupdated_atフィールドを持つもの。

PostgresのBooks.all.group('author_id')のような単純なアプローチの問題は、GROUP BYブロックにすべての要求フィールドが必要なことです。 (https://stackoverflow.com/a/6106195/1245302を参照してください)

しかし、すべてのブックオブジェクトを作成者ごとに取得する必要があります。最近のものは、他のすべてのフィールドを無視します。 DBMSが必要とする行を正確に見つけるのに十分なデータがあると思われます。 少なくとも私はGROUP BYブロック内の他のフィールドなしで自分自身でそれを行うことができます。 :)

Rails 3 + Postgres(バージョン< 9)またはSQL実装 は独立した方法で入手できますか? Postgresのための

UPDATE ニースソリューション:

books.unscoped.select('DISTINCT ON(author_id) *').order('author_id').order('updated_at DESC') 

しかし!まだ問題が残っています - 結果は最初にauthor_idでソートされていますが、同じ -sの中にupdated_atでソートする必要があります(最近のトップ10の著者を見つけるには)。

そして、Postgresはあなたが、私はRailsのを知って、うまくいけば、あなたが道にあなたを得るのを助けるしたいもののためにあなたのSQLを示していないDISTINCTクエリ:(

+0

スピーキングを使用する - ですそれはPostgreSQLまたはあなたが探しているルビーの配列ですか? – vyegorov

+0

私は、Railsモデルオブジェクトの配列が必要です。PostgreSQL 8.4 – aristofun

答えて

1

ORDER BY引数の順序を変更することはできません。 。右のSQLを生成する

SELECT DISTINCT ON (author_id) * 
    FROM Books 
    ORDER BY author_id, updated_at DESC; 

DISTINCT ON (author_id)部分は、結果の列リストの一部と混同してはならない - それはちょうどAUTHOR_IDごとに1つの行があるだろうと述べているDISTINCT ON句のリストでなければなりません。 ORDER BY句の先頭部分このような問合せは、ORDER BYrestに基づいて最初にソートされた行が保持されます。

多くの行を使用すると、クエリを書くこの方法は、通常、GROUP BYまたはウィンドウ関数に基づくソリューションよりもはるかに高速です。しかし、PostgreSQLの拡張機能です。ポータブルであることが意図されているコードでは使用しないでください。

この結果セットを別のクエリ内で使用する場合(たとえば、最近更新された10人の著者を見つける場合など)、2つの方法があります。

WITH w AS (
    SELECT DISTINCT ON (author_id) * 
    FROM Books 
    ORDER BY author_id, updated_at DESC) 
SELECT * FROM w 
    ORDER BY updated_at DESC 
    LIMIT 10; 

のCTEは、ここに保持に関する通常のアドバイス:他がない場合にのみ、それらを使用します。また、このように、CTEを使用することができ

SELECT * 
    FROM (SELECT DISTINCT ON (author_id) * 
      FROM Books 
      ORDER BY author_id, updated_at DESC) w 
    ORDER BY updated_at DESC 
    LIMIT 10; 

:あなたはこのようなサブクエリを使用することができます最適化の障壁を導入してプランナを強制的に執行する必要がある場合は、クエリを記述する方法があります。計画は非常に似ていますが、中間結果をCTEスキャンに渡すことで少しのオーバーヘッドが追加されます。私の小さなテストセットでは、CTEフォームは17%遅くなります。

+0

上記のRailsを生成する方法はありますか? – kgrittn

+0

ありがとう、私はそれをRailsで生成する方法を見つけました。 'books.unscoped.select( 'DISTINCT ON(author_id)*')order( 'author_id')。order( 'updated_at DESC')' – aristofun

+1

could注文の問題で私を助けてください? – aristofun

0

これは遅ればせながらですが、デフォルトの順序をリセット/オーバーライドについての質問に応じて、_array_の.reorder(nil).order(:whatever_you_want_instead)

(私は今の答えとして投稿し、コメントすることはできません)

関連する問題