SQL数据处理,字符串先拆分后合并

目录

需求


以上数据样例,需要转为:

实际业务数据可能不止以上两列,而且数据量比较大,实现时要考虑性能。
本文用SQL实现。

思路

看上去是简单的字符串拆分,实际是每隔两个分隔符(\)进行拆分,而且要将没拆分的分隔符符号转为冒号(:)。可以考虑先全部拆分再每两个进行合并。

代码

/***  第一步,移除多余字符,方便后续折分   ***/
-- update invalid splitor, "/ -> / 
update dbo.physcial_checkup 
set check_result = replace(check_result,'"/','/') 
where charindex('"/',check_result) > 0;

-- remove first char / and last char \
update dbo.physcial_checkup 
set check_result = SUBSTRING(check_result,2,len(check_result) - 2);
/***  第二步,全部拆分为多行   ***/
-- split to temp table
select  a.id
       ,a.check_result
       ,b.[value] as check_result_split
	   ,CEILING(b.ID/2.0) as group_id  -- 每两个一组,方便后续合并
	   ,ROW_NUMBER() over(partition by a.id order by b.id) as rn
into #temp_split
from dbo.physcial_checkup  a
cross apply dbo.SplitString(check_result,'\') as b; 
/***  第三步,列值合并   ***/
select distinct
     a.id
	,stuff((select N':' + check_result_split from #temp_split 
	        where id = a.id  and group_id = a.group_id 
			order by id,rn
			for xml path('')),1,1,'') as check_result
from #temp_split a;

说明

  • 以上第三步列值合并是在SQL Server 2017之前的常见写法,2017版本及之后有新函数STRING_AGG,性能应该会快很多。
  • 以上代码中的group_id是用来后续进行合并的辅助列,每连续两个ID同一组
  • 在不使用STRING_AGG的情况下,提升第三步的性能可以考虑:
    • 增加索引 create index (id,group_id) include (check_result_split),这样子查询可走索引
    • 由于本案例是每个ID按相同Group_ID进行合并,且每个Group两行,合并规则非常固定,可考虑改变写法,只访问一次表即可,按行号分别将同组的两行转为列,最后再拼接:
	    /***  第三步,列值合并   ***/
		select id,group_id
		      ,max(case rn % 2 when 1 then check_result_split end)  + N':' + 
		       max(case rn % 2 when 0 then check_result_split end) as check_result
		from #temp_split a
		group by id,group_id;
  • 第二步比较花时间,SplitString是字符串拆分为多行的函数,可参考此文