簡體   English   中英

SQL:如何將每組 N 行連接成一行

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM