【问题标题】:postgres STRING_AGG() returns duplicates?postgres STRING_AGG() 返回重复项?
【发布时间】:2020-04-12 14:52:14
【问题描述】:

我看到了一些类似的帖子,要求获得从查询中获得不同结果的建议。这可以通过子查询解决,但我正在聚合的列image_name 是唯一的image_name VARCHAR(40) NOT NULL UNIQUE。我不认为这应该是necerarry。

这是 spot_images 表中的数据

spotdk=# select * from spot_images;
 id | user_id | spot_id |              image_name              
----+---------+---------+--------------------------------------
  1 |       1 |       1 | 81198013-e8f8-4baa-aece-6fbda15a0498
  2 |       1 |       1 | 21b78e4e-f2e4-4d66-961f-83e5c28d69c5
  3 |       1 |       1 | 59834585-8c49-4cdf-95e4-38c437acb3c1
  4 |       1 |       1 | 0a42c962-2445-4b3b-97a6-325d344fda4a
(4 rows)
SELECT Round(Avg(ratings.rating), 2) AS rating, 
       spots.*, 
       String_agg(spot_images.image_name, ',') AS imageNames
FROM   spots 
       FULL OUTER JOIN ratings 
                    ON ratings.spot_id = spots.id 
       INNER JOIN spot_images 
               ON spot_images.spot_id = spots.id 
WHERE  spots.id = 1 
GROUP  BY spots.id; 

这是图像行的结果:

81198013-e8f8-4baa-aece-6fbda15a0498,
21b78e4e-f2e4-4d66-961f-83e5c28d69c5,
59834585-8c49-4cdf-95e4-38c437acb3c1,
0a42c962-2445-4b3b-97a6-325d344fda4a,
81198013-e8f8-4baa-aece-6fbda15a0498,
21b78e4e-f2e4-4d66-961f-83e5c28d69c5,
59834585-8c49-4cdf-95e4-38c437acb3c1,
0a42c962-2445-4b3b-97a6-325d344fda4a,
81198013-e8f8-4baa-aece-6fbda15a0498,
21b78e4e-f2e4-4d66-961f-83e5c28d69c5,
59834585-8c49-4cdf-95e4-38c437acb3c1,
0a42c962-2445-4b3b-97a6-325d344fda4a

没有换行符,我添加它们是为了可见性。

我应该怎么做才能每次检索一次 image_name?

【问题讨论】:

  • 由于 FULL OUTER 连接而返回重复项。如果你只加入了 spot 和 spot_images 那么你就不会得到重复。
  • @forpas 你的意思是独立的join 没有外/内/左/右限定符吗?

标签: sql postgresql join group-by average


【解决方案1】:

如果您不想重复,请使用DISTINCT

   String_agg(distinct spot_images.image_name, ',') AS imageNames

【讨论】:

  • 这既快速又简单——为什么需要这样做?为什么只有 4 条记录却聚合了 11 条以上?
  • @JonasGrønbek 。 . .聚合函数聚合整个集合,包括重复值。如果你想要distinct,你需要明确。
  • 为什么整个集合有4个以上的image_names?
  • @JonasGrønbek 。 . .您的数据中有重复项,或者您没有正确的JOIN 条件。
【解决方案2】:

ratings 中可能有几行与给定的spot 匹配,spot_images 中的几行也与给定的sport 匹配。结果,行变得重复。

避免这种情况的一种选择是在子查询中聚合:

SELECT r.avg_raging
       s.*, 
       si.image_names
FROM   spots s
       FULL OUTER JOIN (
           SELECT spot_id, Round(Avg(ratings.rating), 2) avg_rating
           FROM ratings
           GROUP BY spot_id
       ) r ON r.spot_id = s.id
       INNER JOIN (
           SELECT spot_id, string_agg(spot_images.image_name, ',') image_names
           FROM spot_images
           GROUP BY spot_id
       ) si ON si.spot_id = s.id 
WHERE  s.id = 1 

这实际上可能比外部聚合更有效。

注意:如果不查看您的数据,很难判断,但我不确定您是否真的需要FULL JOINLEFT JOIN 可能正是您想要的。

【讨论】:

    猜你喜欢
    • 2021-12-23
    • 2016-01-26
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 2016-05-08
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多