微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL-在多列中拆分字符串

如何解决SQL-在多列中拆分字符串

我想从查询中拆分结果并在单独的列中显示值。作为示例,我得到以下结果

|Name          |
|ABC_DEFG_HIJKL|
|A_B_C         |
|A_B_C_D       |

我想用'_'分割值并将它们添加到单独的列中。 查询结果应该看起来像这样

|Name          |first   |second   |third   |fourth|
|ABC_DEFG_HIJKL|ABC     |DEFG     |HIJKL   |null  |
|A_B_C         |A       |B        |C       |null  |
|A_B_C_D       |A       |B        |C       |D     |

到目前为止,我可以拆分结果。但是对于每个值,我都有一个新行。因此,我只需要将结果合并为一行,并为每行创建一列。

SELECT DP.Name,value  
FROM RitopDatenpunkt DP  
    CROSS APPLY STRING_SPLIT(DP.Name,'_'); 


|Name          |value   |
|ABC_DEFG_HIJKL|ABC     |
|ABC_DEFG_HIJKL|DEFG    |
|ABC_DEFG_HIJKL|HIJKL   |
|A_B_C         |A       |
|A_B_C         |B       |
|A_B_C         |C       |
|A_B_C_D       |A       |
|A_B_C_D       |B       |
|A_B_C_D       |C       |
|A_B_C_D       |D       |

我知道我应该使用PIVOT。但是我要使用什么集成函数,并且FOR语句的参数是正确的

SELECT DP.Name,'_')
PIVOT
(
        GROUPING(Name) as Name
        FOR value in ([first],[second],[third],[fourth])
)piv;

解决方法

假设字符串中没有重复项,则可以使用这种相当繁琐的方法:

select sportsman_id,min(competition_id),max(competition_id),comps_in_island
from (
 select  competition_id,sportsman_id,hold_date,island,count(*) over (partition by sportsman_id,island) comps_in_island
 from (
  select  competition_id,comp_number -row_number() over(partition by sportsman_id order by comp_number) island
  from (  
   select  competition_id,dense_rank() over (partition by null order by competition_id) comp_number
   from    result
  )
 )
)
where comps_in_island > 1
group by sportsman_id,comps_in_island;

这使用SELECT dp.*,s.* FROM RitopDatenpunkt DP CROSS APPY (SELECT MAX(CASE WHEN SEQNUM = 1 THEN s.value END) as first,MAX(CASE WHEN SEQNUM = 2 THEN s.value END) as second,MAX(CASE WHEN SEQNUM = 3 THEN s.value END) as third,MAX(CASE WHEN SEQNUM = 4 THEN s.value END) as fourth FROM (SELECT s.*,ROW_NUMBER() OVER (ORDER BY CHARINDEX('_' + s.value + '_','_' + DP.Name + '_')) as seqnum FROM STRING_SPLIT(DP.Name,'_') s ) s ) s; 查找原始字符串中的值,然后使用条件聚合按顺序创建列。

不幸的是,CHARINDEX()不能保证顺序。另一种方法是,如果没有四个以上的组件,则使用递归CTE或滥用PARSENAME()函数。

,

这是使用JSON函数的一种方法:

select t.name,json_value(x.obj,'$[0]') name1,'$[1]') name2,'$[2]') name2,'$[3]') name4
from mytable t
cross apply (values('["' + replace(t.name,'_','","') + '"]')) x(obj)

技巧是操纵字符串以使其看起来像JSON数组(这就是cross apply子查询的作用)。基本上,这会将类似'A_B_C'的字符串转换为'["A","B","C"]'。然后,我们可以使用json_value()轻松访问每个元素。

这不假定元素具有唯一性。实际上,唯一的要求是该字符串不应包含嵌入的双引号。

Demo on DB Fiddle

name           | name1 | name2 | name2 | name4
:------------- | :---- | :---- | :---- | :----
ABC_DEFG_HIJKL | ABC   | DEFG  | HIJKL | null 
A_B_C          | A     | B     | C     | null 
A_B_C_D        | A     | B     | C     | D    
,

您也可以将PARSENAME()用作:

SELECT Val,PARSENAME(Value,1) Name1,2) Name2,3) Name3,4) Name4
FROM
(
  VALUES
  ('ABC_DEFG_HIJKL'),('A_B_C'),('A_B_C_D')
) T(Val) CROSS APPLY (VALUES(REPLACE(Val,'.'))) TT(Value);

请注意,如果您的'_'数超过3,则此方法将无效。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。