Sql 服务器:限制 string_agg 结果
Sql server: limit string_agg result
我有以下查询(为每个客户显示用户列表):
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
如何限制 string_agg 函数为每个组仅聚合 10 个元素?
您可以尝试对行进行编号:
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
我们可以在 sub-query 中使用 row_number。我在这个例子中限制为 2,您可以将 rn 的限制更改为 10 或其他数字。
我显示第一个查询没有限制,第二个查询有限制以显示差异。
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 行受影响
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
这又是另一种情况,我发现在 CTE 中分离逻辑的“丑陋”部分(串联并确定“第一个”或“任何”10),然后直到之后才聚合:
; -- 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;
我有以下查询(为每个客户显示用户列表):
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
如何限制 string_agg 函数为每个组仅聚合 10 个元素?
您可以尝试对行进行编号:
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
我们可以在 sub-query 中使用 row_number。我在这个例子中限制为 2,您可以将 rn 的限制更改为 10 或其他数字。
我显示第一个查询没有限制,第二个查询有限制以显示差异。
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 行受影响
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
这又是另一种情况,我发现在 CTE 中分离逻辑的“丑陋”部分(串联并确定“第一个”或“任何”10),然后直到之后才聚合:
; -- 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;