一尘不染

JOIN返回重复项后的GROUP或DISTINCT

sql

我有两个表,productsmeta。它们之间的关系为1:N,其中每个产品行都通过外键具有至少一个元行。

(即SQLfiddle:http
://sqlfiddle.com/#!15/c8f34/1 )

我需要加入这两个表,但是我只需要过滤唯一的产品。当我尝试此查询时,一切正常(返回4行):

SELECT DISTINCT(product_id)
FROM meta JOIN products ON products.id = meta.product_id

但是当我尝试选择所有列时,DISTINCT规则不再适用于结果,因为返回的是8行而不是4行。

SELECT DISTINCT(product_id), *
FROM meta JOIN products ON products.id = meta.product_id

我尝试了很多方法,例如尝试DISTINCTGROUP BY对子查询进行尝试,但总是得到相同的结果。


阅读 130

收藏
2021-03-10

共1个答案

一尘不染

虽然检索全部或大部分行从表中,对于这种类型的查询最快的方法通常是聚合/歧义 第一 和加入

SELECT *
FROM   products p
JOIN  (
   SELECT DISTINCT ON (product_id) *
   FROM   meta
   ORDER  BY product_id, id DESC
   ) m ON m.product_id = p.id;

meta每行中的行越多products,对性能的影响越大。

当然,您需要ORDER BY在子查询中添加一个子句,以定义从子查询中的每个集合中选择 哪一
行。@Craig和@Clodoaldo已经告诉过您。我将返回meta最高的行id

SQL提琴。

优化性能

尽管如此,这并不总是最快的解决方案。根据数据分布,还有其他各种查询样式。对于涉及另一个联接的这种简单情况,在带有大表的测试中,该联接的运行速度大大提高:

SELECT p.*, sub.meta_id, m.product_id, m.price, m.flag
FROM  (
   SELECT product_id, max(id) AS meta_id
   FROM   meta
   GROUP  BY 1
   ) sub
JOIN meta     m ON m.id = sub.meta_id
JOIN products p ON p.id = sub.product_id;

如果您不将非描述性id名称用作列名,那么我们就不会遇到命名冲突,只需编写即可SELECT p.*, m.*。(我 从来没有
使用id的列名。)

如果性能是您的首要要求,请考虑更多选择:

  • 如果您的数据没有变化(很多),则其中MATERIALIZED VIEW包含来自的预汇总数据meta
  • 递归CTE,模拟对每个产品有 很多 行的 表的 松散索引扫描 (相对而言,很少有不同的)。 这是我知道对整个表的DISTINCT查询使用索引的唯一方法。 meta product_id
2021-03-10