Home > Enterprise >  Sql server: limit string_agg result
Sql server: limit string_agg result

Time:05-02

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;

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

  • Related