![](/img/trans.png)
[英]SQL/Postgres - collapse every N rows into 1 based on row position in group
[英]SQL: How to concatenate every group of N rows into a single row
我有这个
ID | Name
----+-------
31 | Abby
24 | Bruce
44 | Carl
49 | Derek
55 | Eric
81 | Fred
我想将 N 行组连接成一行。 对于 N = 3,这会给我这个
ID | Name
----------+----------------
31,24,44 | Abby,Bruce,Carl
49,55,81 | Derek,Eric,Fred
我设法生成一行以使用 GROUP BY 和 CONCAT,但它仅适用于 mysql ...
SET @row_number = 0;
SELECT *, (@row_number:=@row_number + 1) AS r1, (@row_number - 1) DIV 3 AS r2 FROM table1
ID | Name | r1| r2
----+-------+---+---
31 | Abby | 1 | 0
24 | Bruce | 2 | 0
44 | Carl | 3 | 0
49 | Derek | 4 | 1
55 | Eric | 5 | 1
81 | Fred | 6 | 1
为了澄清:
我想要一个类似 vanilla 的 SQL 解决方案(所以它可以在 mysql、sybase、oracle 和 postgres 中工作)
我不需要任何命令,我只是想在某个时候重组原始表
我在此基础上没有写作权限,只有阅读权限
我想连接任何列类型(通过将它们转换为字符串)并处理 NULL
如果某些组的大小不完全是 N 也没关系(就像最后一个一样)
标准的 SQL 解决方案如下所示:
select listagg(id, ',') within group (order by id) as ids,
listagg(name, ',') within group (order by id) as names
from (select t.*, row_number() over (order by id) as seqnum
from t
) t
group by cast( (seqnum - 1) / 3 as int);
我认为这将在 Oracle 中按原样工作。 在 MySQL 中,您需要将listagg()
更改为group_concat()
(并且使用 MySQL 8+),在 Postgres 中,您需要将listagg()
更改为string_agg()
。
而且,您在 Sybase 中几乎无法轻松做到这一点。
哦,等等,还有一种方法:
select concat( (case when seqnum % 3 = 1 then concat(id, ';') else '' end),
(case when seqnum % 3 = 2 then concat(id, ';') else '' end),
(case when seqnum % 3 = 0 then concat(id, ';') else '' end)
) as ids,
concat( (case when seqnum % 3 = 1 then concat(name, ';') else '' end),
(case when seqnum % 3 = 2 then concat(name, ';') else '' end),
(case when seqnum % 3 = 0 then concat(name, ';') else '' end)
) as name
from (select t.*, row_number() over (order by id) as seqnum
from t
) t
group by cast( (seqnum - 1) / 3 as int);
当然,Sybase 不支持concat()
,所以你必须使用+
。 这产生;
对于分隔符而不是,
,但它非常接近。
惊人的剧本。 但我怀疑你遗漏了一个 AS。 所以我是这样制作的:
选择 string_agg(t.[id], ',') 作为 ids, string_agg(t.[name], ',') 作为名称来自
(选择 t.*, row_number() over (order by id) as seqnum from [tablename] ) AS t
group by cast((seqnum - 1) / 3 as int);
就我而言,就是这样(尽管我无法让“组内(按 ID 排序)”以任何方式工作......嗯)
这是我的效果很好,它是发给我所有学生的电子邮件列表,每 100 行合并成一行。 遗憾的是,String_Agg 将其限制为 8000 个字符。 任何人都知道 SQL Server 的 String_Agg 的替代品吗?
SELECT string_agg(t.[Student Name], ';') as [All Names], string_agg(t.[Student Email], ';') as [All Emails]
FROM ( SELECT [Student Name], [Student Email], ROW_NUMBER() OVER (ORDER BY [Student Email]) AS RowNo FROM [Mailing List For Courses] where [Prod Name]='Online Courses') AS t group by cast ( (RowNo - 1) / 100 作为 int);
希望有帮助 <3
我有这个
ID | Name
----+-------
31 | Abby
24 | Bruce
44 | Carl
49 | Derek
55 | Eric
81 | Fred
我想将N行的组连接成单行。 对于N = 3,这会给我这个
ID | Name
----------+----------------
31,24,44 | Abby,Bruce,Carl
49,55,81 | Derek,Eric,Fred
我设法生成一行以在其上使用GROUP BY和CONCAT,但是它仅适用于mysql ...
SET @row_number = 0;
SELECT *, (@row_number:=@row_number + 1) AS r1, (@row_number - 1) DIV 3 AS r2 FROM table1
ID | Name | r1| r2
----+-------+---+---
31 | Abby | 1 | 0
24 | Bruce | 2 | 0
44 | Carl | 3 | 0
49 | Derek | 4 | 1
55 | Eric | 5 | 1
81 | Fred | 6 | 1
为了澄清:
我想要一个类似香草的SQL解决方案(因此它将在mysql,sybase,oracle和postgres中工作)
我不需要任何命令,我只想在某个时候重构原始表
在此基础上,我没有写权限,只能阅读
我想连接任何列类型(通过将它们转换为字符串)并处理NULL
如果某些组的大小不完全是N也可以(例如最后一个)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.