sql 聚合和拆分
sql aggregate and split
我有这个 table Table_1 :
pk Column_1
1 addcd
2 swrrh
3 dggdd
4 wdffa
我想将结果合并并拆分为 4 个字母,这样 return 就像这样
addc
dswr
rhdg
gddw
dffa
注意:剩下的字母将被丢弃
我尝试使用 string_agg
,但我不知道下一步该做什么。
这使用 STRING_AGG
将字符串聚合成一个长字符串,然后使用 Tally Table 拆分为新行。 假定 您有一个列可以排序。如果你不这样做,你就无法实现你想要的,因为 table 中的数据存储在 无序 堆中。
CREATE TABLE dbo.YourTable (YourID int IDENTITY,
Yourcolumn varchar(5));
INSERT INTO dbo.YourTable (Yourcolumn)
VALUES('addcd'),
('swrrh'),
('dggdd'),
('wdffa');
GO
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS I
FROM N N1, N N2, N N3, N N4), --This is likely over kill here, but I've assumed you'll have a much larger data set
Agg AS(
SELECT STRING_AGG(YT.YourColumn,'') WITHIN GROUP (ORDER BY YT.YourID) AS YourString
FROM dbo.YourTable YT)
SELECT SUBSTRING(A.YourString,(I*4)+1,4)
FROM Tally T
CROSS JOIN Agg A
WHERE SUBSTRING(A.YourString,(I*4)+1,4) <> '';
GO
DROP TABLE dbo.YourTable;
此解决方案适用于旧版本的 SQL 服务器。 Larnu 的回答在更新的版本中是正确的。
让我们使用递归 CTE。这个想法是创建一个大字符串,然后将其切成小块。太好玩了!
with tt as (
select t.*, row_number() over (order by pk) as seqnum
from t
),
bigstring as (
select convert(varchar(max), column_1) as bigstring, seqnum
from tt
union all
select concat(bigstring.bigstring, tt.column_1), tt.seqnum
from bigstring join
tt
on tt.seqnum = bigstring.seqnum + 1
),
string4 as (
select top (1) left(bigstring, 4) as string4, stuff(bigstring, 1, 4, '') as rest4, 1 as lev
from bigstring
order by len(bigstring.bigstring) desc
union all
select left(rest4, 4), stuff(rest4, 1, 4, ''), lev + 1
from string4
where rest4 > ''
)
select string4.string4
from string4
order by lev;
一个查询中有两个递归 CTE!
Here 是一个 db<>fiddle.
我有这个 table Table_1 :
pk Column_1
1 addcd
2 swrrh
3 dggdd
4 wdffa
我想将结果合并并拆分为 4 个字母,这样 return 就像这样
addc
dswr
rhdg
gddw
dffa
注意:剩下的字母将被丢弃
我尝试使用 string_agg
,但我不知道下一步该做什么。
这使用 STRING_AGG
将字符串聚合成一个长字符串,然后使用 Tally Table 拆分为新行。 假定 您有一个列可以排序。如果你不这样做,你就无法实现你想要的,因为 table 中的数据存储在 无序 堆中。
CREATE TABLE dbo.YourTable (YourID int IDENTITY,
Yourcolumn varchar(5));
INSERT INTO dbo.YourTable (Yourcolumn)
VALUES('addcd'),
('swrrh'),
('dggdd'),
('wdffa');
GO
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1 AS I
FROM N N1, N N2, N N3, N N4), --This is likely over kill here, but I've assumed you'll have a much larger data set
Agg AS(
SELECT STRING_AGG(YT.YourColumn,'') WITHIN GROUP (ORDER BY YT.YourID) AS YourString
FROM dbo.YourTable YT)
SELECT SUBSTRING(A.YourString,(I*4)+1,4)
FROM Tally T
CROSS JOIN Agg A
WHERE SUBSTRING(A.YourString,(I*4)+1,4) <> '';
GO
DROP TABLE dbo.YourTable;
此解决方案适用于旧版本的 SQL 服务器。 Larnu 的回答在更新的版本中是正确的。
让我们使用递归 CTE。这个想法是创建一个大字符串,然后将其切成小块。太好玩了!
with tt as (
select t.*, row_number() over (order by pk) as seqnum
from t
),
bigstring as (
select convert(varchar(max), column_1) as bigstring, seqnum
from tt
union all
select concat(bigstring.bigstring, tt.column_1), tt.seqnum
from bigstring join
tt
on tt.seqnum = bigstring.seqnum + 1
),
string4 as (
select top (1) left(bigstring, 4) as string4, stuff(bigstring, 1, 4, '') as rest4, 1 as lev
from bigstring
order by len(bigstring.bigstring) desc
union all
select left(rest4, 4), stuff(rest4, 1, 4, ''), lev + 1
from string4
where rest4 > ''
)
select string4.string4
from string4
order by lev;
一个查询中有两个递归 CTE!
Here 是一个 db<>fiddle.