I have the following query (showing for each customer the list of users):
select cu.customer_id , STRING_AGG(u.first_name ' ' u.last_name , ',') as users
from customer_user cu join user u on cu.user_id = u.id
where ...
group by cu.customer_id
How can I limit the string_agg function to aggregate only 10 elements for each group?
CodePudding user response:
You may try to number the rows:
SELECT customer_id , STRING_AGG(first_name ' ' last_name , ',') AS users
FROM (
SELECT
cu.customer_id, u.first_name, u.last_name,
ROW_NUMBER() OVER (PARTITION BY cu.customer_id ORDER BY (SELECT NULL)) AS rn
FROM customer_user cu
JOIN user u ON cu.user_id = u.id
-- WHERE ...
) t
WHERE rn <= 10
GROUP BY customer_id
CodePudding user response:
Again this is another case where I find separating the "ugly" part of the logic (concatenation and determining "first" or "any" 10) in a CTE, then not aggregating until after:
; -- see sqlblog.org/cte
WITH src AS
(
SELECT cu.customer_id, n = CONCAT(u.first_name, ' ', u.last_name),
rn = ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY @@SPID)
FROM dbo.customer_user AS cu
INNER JOIN dbo.[user] AS u -- bad table name
ON cu.user_id = u.id
/* WHERE ... */
)
SELECT customer_id, users = STRING_AGG(n, N',')
FROM src
WHERE rn <= 10
GROUP BY customer_id;
- Example db<>fiddle
CodePudding user response:
We can use row_number in a sub-query. I have limited to 2 in this example and you can change the limit for rn as to 10, or other number.
I show the first query without a limit and the second with a limit to show the difference.
create table users( id int, first_name varchar(25), last_name varchar(25) ); insert into users values (1,'Andrew','A'), (2,'Bill','B'), (3,'Charlie','C'); create table customer_user( customer_id int, user_id int); insert into customer_user values (1,1),(1,2),(1,3); GO
6 rows affected
select cu.customer_id , STRING_AGG(u.first_name ' ' u.last_name , ',') as users from customer_user cu join users u on cu.user_id = u.id group by cu.customer_id
GO
customer_id | users ----------: | :------------------------ 1 | Andrew A,Bill B,Charlie C
select u.customer_id , STRING_AGG(u.first_name ' ' u.last_name , ',') as users from ( select row_number() over(partition by customer_id order by u.id) rn, cu.customer_id, u.first_name, u.last_name from customer_user cu join users u on cu.user_id = u.id ) u where rn < 3 group by u.customer_id GO
customer_id | users ----------: | :-------------- 1 | Andrew A,Bill B
db<>fiddle here