将行连接成列(NO FOR XML PATH('') 和递归 CTE)- SQL Server 2012
Concatenate rows into columns (NO FOR XML PATH('') and recursive CTEs) - SQL Server 2012
我手头有一个非常特殊的问题。
简介:我在数据库中有两列需要 "group concatenate",在 MySQL 我会简单地使用 GROUP_CONCAT
来获得所需的结果,在 [=40] =] Server 2017 和我会使用 STRING_AGG
,我遇到的问题是 SQL Server 2012,它没有这个功能。
现在,在正常情况下我会使用 FOR XML PATH('')
来获得解决方案,这是不可行的,因为我 运行 来自第三个源应用程序中的编辑器的查询,错误是我得到的是
FOR XML PATH('') can't be used inside a cursor
为了论证,我们假设使用这个函数是完全不可能的。
我试过使用递归CTE,但是,由于执行时间,它不可行,UNION ALL
占用太多资源,无法正常执行(我正在使用数据进行报告)。
由于数据的敏感性,我不会post数据的屏幕截图,假设只有两列,一列有一个 id(多个相同的 id),一列有需要的数据要连接(一些字符串)。目标是将第一列中所有相同 ID 的第二列连接起来,显然在这个过程中使它与众不同。
示例:
输入:
col1 col2
1 a
1 b
2 a
3 c
输出:
col1 col2
1 a/b
2 a
3 c
有没有人对如何做到这一点有创意?
您的示例输出似乎有误,因为 'a/b' 应该是值 2。
尝试以下操作:
declare @t table (col1 int, col2 varchar(100))
insert into @t select 1, 'a'
insert into @t select 2, 'b'
insert into @t select 2, 'a'
insert into @t select 3, 'c'
declare @final_table table (col1 int, col2 varchar(100), col2_all varchar(1000))
insert into @final_table (col1, col2)
select * from @t
declare @col2_all varchar(1000)
declare @Name sysname
update @final_table
SET @col2_all = col2_all = COALESCE(CASE COALESCE(@Name, '')
WHEN col1 THEN @col2_all + '/' + col2
ELSE col2 END, ''),
@Name = col1;
select col1, col2_grouped = MAX(col2_all)
from @final_table
group by col1
使用 CTE:
;with cte(col1,col2_grouped,rn)
as
(
select col1, col2 , rn=ROW_NUMBER() over (PARTITION by col1 order by col1)
from @t
)
,cte2(col1,final_grouped,rn)
as
(
select col1, convert(varchar(max),col2_grouped), 1 from cte where rn=1
union all
select cte2.col1, convert(varchar(max),cte2.final_grouped+'/'+cte.col2_grouped), cte2.rn+1
from cte2
inner join cte on cte.col1 = cte2.col1 and cte.rn=cte2.rn+1
)
select col1, MAX(final_grouped) col2_grouped from cte2 group by col1
请参阅db<>fiddle here。
如果您知道需要连接在一起的最大值数,则可以使用条件聚合:
select col1,
stuff( concat(max(case when seqnum = 1 then '/' + col2 end),
max(case when seqnum = 2 then '/' + col2 end),
max(case when seqnum = 3 then '/' + col2 end),
max(case when seqnum = 4 then '/' + col2 end),
max(case when seqnum = 5 then '/' + col2 end)
), 1, 1, ''
) as col2s
from (select t.*,
row_number() over (partition by col1 order by col2) as seqnum
from t
) t
group by col1;
您可以使用以下方式获得最大数量:
select top (1) count(*)
from t
group by col1;
我手头有一个非常特殊的问题。
简介:我在数据库中有两列需要 "group concatenate",在 MySQL 我会简单地使用 GROUP_CONCAT
来获得所需的结果,在 [=40] =] Server 2017 和我会使用 STRING_AGG
,我遇到的问题是 SQL Server 2012,它没有这个功能。
现在,在正常情况下我会使用 FOR XML PATH('')
来获得解决方案,这是不可行的,因为我 运行 来自第三个源应用程序中的编辑器的查询,错误是我得到的是
FOR XML PATH('') can't be used inside a cursor
为了论证,我们假设使用这个函数是完全不可能的。
我试过使用递归CTE,但是,由于执行时间,它不可行,UNION ALL
占用太多资源,无法正常执行(我正在使用数据进行报告)。
由于数据的敏感性,我不会post数据的屏幕截图,假设只有两列,一列有一个 id(多个相同的 id),一列有需要的数据要连接(一些字符串)。目标是将第一列中所有相同 ID 的第二列连接起来,显然在这个过程中使它与众不同。
示例: 输入:
col1 col2
1 a
1 b
2 a
3 c
输出:
col1 col2
1 a/b
2 a
3 c
有没有人对如何做到这一点有创意?
您的示例输出似乎有误,因为 'a/b' 应该是值 2。
尝试以下操作:
declare @t table (col1 int, col2 varchar(100))
insert into @t select 1, 'a'
insert into @t select 2, 'b'
insert into @t select 2, 'a'
insert into @t select 3, 'c'
declare @final_table table (col1 int, col2 varchar(100), col2_all varchar(1000))
insert into @final_table (col1, col2)
select * from @t
declare @col2_all varchar(1000)
declare @Name sysname
update @final_table
SET @col2_all = col2_all = COALESCE(CASE COALESCE(@Name, '')
WHEN col1 THEN @col2_all + '/' + col2
ELSE col2 END, ''),
@Name = col1;
select col1, col2_grouped = MAX(col2_all)
from @final_table
group by col1
使用 CTE:
;with cte(col1,col2_grouped,rn)
as
(
select col1, col2 , rn=ROW_NUMBER() over (PARTITION by col1 order by col1)
from @t
)
,cte2(col1,final_grouped,rn)
as
(
select col1, convert(varchar(max),col2_grouped), 1 from cte where rn=1
union all
select cte2.col1, convert(varchar(max),cte2.final_grouped+'/'+cte.col2_grouped), cte2.rn+1
from cte2
inner join cte on cte.col1 = cte2.col1 and cte.rn=cte2.rn+1
)
select col1, MAX(final_grouped) col2_grouped from cte2 group by col1
请参阅db<>fiddle here。
如果您知道需要连接在一起的最大值数,则可以使用条件聚合:
select col1,
stuff( concat(max(case when seqnum = 1 then '/' + col2 end),
max(case when seqnum = 2 then '/' + col2 end),
max(case when seqnum = 3 then '/' + col2 end),
max(case when seqnum = 4 then '/' + col2 end),
max(case when seqnum = 5 then '/' + col2 end)
), 1, 1, ''
) as col2s
from (select t.*,
row_number() over (partition by col1 order by col2) as seqnum
from t
) t
group by col1;
您可以使用以下方式获得最大数量:
select top (1) count(*)
from t
group by col1;