具有限制的子查询的字段平均值

时间:2016-10-01 01:58:18

标签: sql postgresql aggregate-functions

我无法生成我确信可能的查询。我有一个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个等级值的相同平均值。这似乎ON的{​​{1}}条款不起作用,但我确信这只是我对某些事情的误解。

2 个答案:

答案 0 :(得分:1)

您的问题中有一些解释空间......

您可能希望每个产品rank中30个最低product_changes值的平均值。

除非您想要在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中价值最低的产品和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,您实际上是指 30个product_changes.rank 中值最低的产品:

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;

答案 1 :(得分: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