Reputation: 1109
Is it possible to limit the number of elements in the following string_agg
function?
string_agg(distinct(tag),', ')
Upvotes: 21
Views: 28203
Reputation: 407
Try
array_sample(array_agg(column),count)
if you don't care which rows are given.
Upvotes: 0
Reputation: 656241
To "limit the number of elements in the following string_agg()
", use LIMIT
in a subquery:
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;
The subquery is no problem for performance at all. On the contrary, this is typically faster, even if you don't impose a maximum number with LIMIT
, because the group-wise DISTINCT
in the aggregate function is more expensive than doing it in a subquery for all rows at once.
Or, to get the "100 most common tags":
SELECT string_agg(tag, ', ') AS tags
FROM (
SELECT tag
FROM tbl
GROUP BY tag
ORDER BY count(*) DESC
LIMIT 100
) sub;
Upvotes: 18
Reputation: 4190
There are two more ways.
make an array from rows, limit it, and then concatenate into string:
SELECT array_to_string((array_agg(DISTINCT tag))[1:3], ', ') FROM tbl
("array[1:3]" means: take items from 1 to 3 from array)
concatenate rows into string without limit, then use "substring" to trim it:
string_agg(distinct(tag),',')
If you know that your "tag" field cannot contain ,
character then you can select all text before nth occurence of your ,
SELECT substring(
string_agg(DISTINCT tag, ',') || ','
from '(?:[^,]+,){1,3}')
FROM tbl
This substring will select 3 or less strings divided by ,
. To exclude trailing ,
just add rtrim
:
SELECT rtrim(substring(
string_agg(DISTINCT tag, ',') || ','
from '(?:[^,]+,){1,3}'), ',')
FROM test
Upvotes: 31
Reputation: 3090
Nest your string_agg
clause in a split_part
, including the delimiter as the second argument, and the number of elements you need as the final argument. Like so:
split_part(string_agg(distinct(tag),', '), ', ', 1)
Upvotes: 3
Reputation: 1
Use IN to filter
Like This:
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;
Upvotes: 0
Reputation: 1269443
I am not aware that you can limit it in the string_agg()
function. You can limit it in other ways:
select postid, string_agg(distinct(tag), ', ')
from table t
group by postid
Then you can do:
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
Upvotes: 11