2016-10-01 3 views
0

確かに可能なクエリの生成に問題があります。私はproductsテーブルとproduct_changesテーブルを持っています。私はproduct_changes.rankフィールドの平均を各関連製品の上位30個の最小値に選択したいと考えています。ここでサブクエリからのフィールドの平均値の上限

は、関連するテーブル定義です:

SELECT products.id, avg_rank 
FROM "products" 
JOIN (
    SELECT product_id, AVG(rank) avg_rank 
    FROM product_changes 
    GROUP BY product_id, rank 
    ORDER BY rank ASC NULLS LAST 
    LIMIT 10) pc ON pc.product_id = products.id 
WHERE avg_rank IS NOT NULL 
LIMIT 10 

をしかし、これは私の各行の最安30ランク値の同じ平均を与えている。ここで

CREATE TABLE products (
    id integer NOT NULL, 
    created_at timestamp without time zone 
); 

CREATE TABLE product_changes (
    id integer NOT NULL, 
    product_id integer, 
    rank integer, 
    created_at timestamp without time zone 
); 

は私がしようとしているものです結果のそれはJOINONのように思えますが、私は何かを誤解していると確信しています。

+0

をいつものように助けて。あなたは '各製品のランクフィールド'について言及していますが、私はあなたのクエリにその列を表示しません... –

+0

ランクフィールドについてのテーブル定義と説明を含めるように質問が更新されました。ごめんなさい。これはサイドプロジェクトで、ちょうどそれに戻る時間があります。答えを今読んでください。 – dbwinger

+0

目的を明確にすることもできます。 「関連する各製品の上位30個の最小値に対するproduct_changes.rankフィールドの平均」はあいまいです。私はいくつかの*可能な解釈に答えようとしました。あなたが望むものはどれですか?どうか明らかにしてください。 –

答えて

1

おそらく、各製品のproduct_changesで30の最低rank値の平均を求めています。

あなたはproduct_changesに関連する行せずに製品を含めたい場合を除き、あなただけのproduct_changesを見ることで、高速な結果を得ることができます - サブクエリでwindow function row_number()を使用して:

SELECT id, avg(rank) AS avg_rank 
FROM (
    SELECT product_id AS id, rank 
     , row_number() OVER (PARTITION BY product_id ORDER BY rank) AS rn 
    FROM product_changes 
    ) sub 
WHERE rn <= 30 
GROUP BY id; 

それともあなたが30製品を意味products.rankにおける最小値とproduct_changesに関連する行の平均rank

SELECT p.id, pc.avg_rank 
FROM (
    SELECT id 
    FROM products 
    ORDER BY rank 
    LIMIT 30 
    ) p 
LEFT JOIN LATERAL (
    SELECT avg(rank) avg_rank 
    FROM product_changes 
    WHERE product_id = p.id 
    ) pc ON true; 

なぜLEFT JOIN LATERAL ... ON true

そこには列products.rankではありません、あなたが実際にproduct_changes.rankで最も低い値と30製品を意味している場合:、テーブル定義とPostgresのバージョンでしょう

SELECT p.id, pc.avg_rank 
FROM (
    SELECT product_id AS id 
    FROM product_changes 
    ORDER BY rank 
    LIMIT 30 
    ) p 
LEFT JOIN LATERAL (
    SELECT avg(rank) avg_rank 
    FROM product_changes 
    WHERE product_id = p.id 
    ) pc ON true; 
+0

あなたの最初の解決策は、私が探していたものでした。ありがとうございました! – dbwinger

0

LATERALサブクエリまたは相関サブクエリを使用して、サブクエリが各製品に対して確実に実行されるようにします。ここでは例です:...あなたの問題の解釈の余地があり

SELECT products.id, avg_rank 
FROM "products", 
    LATERAL (
     SELECT AVG(rank) avg_rank 
     FROM (SELECT rank 
       FROM product_changes 
       WHERE product_id=products.id 
       ORDER BY rank ASC NULLS LAST 
       LIMIT 30) t1 
    ) t2 
WHERE avg_rank IS NOT NULL 
LIMIT 10 
関連する問題