0

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?

1
  • The first 10 users for each customer, i don't care the order of them. Commented May 2, 2022 at 7:00

3 Answers 3

2

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
Sign up to request clarification or add additional context in comments.

Comments

1

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;

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.