【问题标题】:PostgreSQL - string_agg with limited number of elementsPostgreSQL - 元素数量有限的 string_agg
【发布时间】:2014-12-10 15:46:34
【问题描述】:

下面的string_agg函数可以限制元素个数吗?

 string_agg(distinct(tag),', ')

【问题讨论】:

  • 你能提供剩下的查询吗?您可以使用子查询和row_number 获得结果,但您也可以单独使用limit
  • 你不能限制函数本身,但是,扩展问题,你为什么需要这个?也许我们可以找到另一种方式。
  • 您能否澄清这个问题:您的意思是限制 size 还是 元素数量
  • @ErwinBrandstetter 元素数量。我不想写任何子查询的原因是因为我已经在查询中有了它们。实际上,您帮助我进行了查询,请参阅this 问题。再次感谢您!
  • @nickbusted:即使您已经有子查询,也可以将LIMIT 集成到现有的查询中,或者添加另一个带有LIMIT 的子查询以限制元素的数量。这是您所要求的最有效的答案。窗口函数通常更昂贵。

标签: sql postgresql aggregate-functions


【解决方案1】:

还有两种方法。

1) 从行中创建一个数组,对其进行限制,然后连接成字符串:

SELECT array_to_string((array_agg(DISTINCT tag))[1:3], ', ') FROM tbl

("array[1:3]" 意思是:从数组中取出 1 到 3 的项目)

2) 将行无限制地连接成字符串,然后使用“子字符串”对其进行修剪:

string_agg(distinct(tag),',')

如果您知道您的“标签”字段不能包含 , 字符,那么您可以选择第 n 次出现 , 之前的所有文本

SELECT substring(
string_agg(DISTINCT tag, ',')
from '(?:[^,]+,){1,3}')
FROM tbl

此子字符串将选择 3 个或更少的字符串除以 ,

【讨论】:

  • 喜欢数组方法!
【解决方案2】:

对于limit the number of elements in the following string_agg(),在子查询中使用LIMIT

SELECT string_agg(tag, ', ') AS tags
FROM  (
   SELECT DISTINCT tag
   FROM   tbl
   -- ORDER  BY tag -- optionally order to get deterministic result
   LIMIT   123     -- add your limit here
   ) sub;

请注意,子查询根本不是性能问题。 相反,这通常更快,即使您没有对LIMIT 施加最大数量,因为聚合函数中的分组DISTINCT 更多比一次在所有行的子查询中执行此操作要昂贵。

或者,要获得“100 个最常见的标签”:

SELECT string_agg(tag, ', ') AS tags
FROM  (
   SELECT tag
   FROM   tbl
   GROUP  BY tag
   ORDER  BY count(*) DESC
   LIMIT  100
   ) sub;

【讨论】:

    【解决方案3】:

    我不知道你可以在string_agg() 函数中限制它。您可以通过其他方式对其进行限制:

    select postid, string_agg(distinct(tag), ', ')
    from table t
    group by postid
    

    那么你可以这样做:

    select postid, string_agg(distinct (case when seqnum <= 10 then tag end), ', ')
    from (select t.*, dense_rank() over (partition by postid order by tag) as seqnum
          from table t
         ) t
    group by postid
    

    【讨论】:

    • 谢谢。我宁愿避免更多的子查询。我可能会避免使用 string_agg。
    【解决方案4】:

    string_agg 子句嵌套在split_part 中,包括作为第二个参数的分隔符,以及作为最后一个参数所需的元素数。像这样:

    split_part(string_agg(distinct(tag),', '), ', ', 1)
    

    【讨论】:

      【解决方案5】:

      使用 IN 过滤

      像这样:

      Select
        primaryID,
        String_Agg(email, '|') As Email
      From
        contacts
      Where
        contactID In (Select filter.contactID
        From contacts filter
        Where filter.primaryID = contacts.primaryID
        Order By filter.contactID)
      Group By
        primaryID;
      

      【讨论】:

        猜你喜欢
        • 2020-12-25
        • 2013-12-24
        • 2017-08-01
        • 1970-01-01
        • 2020-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多