2016-10-01 57 views
0

我在生成一個我確信可能的查詢時遇到了問題。我有一個products表和一個product_changes表。我想爲每個關聯產品的前30個最低值選擇product_changes.rank字段的平均值。限制子查詢字段的平均值

下面是相關的表定義:

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 
); 

這裏就是我想:

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個等級值的結果。這看起來像JOINON條款不起作用,但我相信這只是我對某事的誤解。

+0

像往常一樣,表定義和Postgres版本將幫幫我。您提到每個產品的「排名字段」,但我在您的查詢中沒有看到該列... –

+0

已更新的問題包括關於排名字段的表定義和說明。對不起,我花了這麼長時間。這是一個側面項目,只是有時間回到它。現在閱讀答案。 – dbwinger

+0

您可能也想澄清目標。 「每個相關產品的前30個最低值的product_changes.rank字段的平均值是不明確的。我試圖回答*一些*可能的解釋。他們中的一個是你想要的嗎?請澄清。 –

回答

1

有一些空間,在你的問題解釋...

你可能想平均值的30個最低rank值的product_changes每個產品。

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產品:在子查詢中使用window function row_number() -

除非你要包括產品無相關行中product_changes,你可以通過看只product_changes得到快速的結果在products.rank和相關行的平均rank最低值product_changes

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.rank30產品的最低值:

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