SQL-在多列中拆分字符串

SQL-在多列中拆分字符串,sql,sql-server,string,split,sql-server-2019,Sql,Sql Server,String,Split,Sql Server 2019,我希望将查询结果拆分,并在单独的列中显示这些值。作为一个例子,我得到以下结果 |Name | |ABC_DEFG_HIJKL| |A_B_C | |A_B_C_D | 我想将这些值按‘‘’分割,并将它们添加到单独的列中。 查询结果应该如下所示 |Name |first |second |third |fourth| |ABC_DEFG_HIJKL|ABC |DEFG |HIJKL |null |

我希望将查询结果拆分,并在单独的列中显示这些值。作为一个例子,我得到以下结果

|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, value  
FROM RitopDatenpunkt DP  
    CROSS APPLY STRING_SPLIT(DP.Name, '_')
PIVOT
(
        GROUPING(Name) as Name
        FOR value in ([first],[second],[third],[fourth])
)piv;

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

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()
查找原始字符串中的值,然后使用条件聚合按顺序创建列


不幸的是,
STRING\u SPLIT()
不能保证排序。另一种方法是使用递归CTE或误用函数(如果组件不超过四个)。

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

select t.name,
    json_value(x.obj, '$[0]') name1,
    json_value(x.obj, '$[1]') name2,
    json_value(x.obj, '$[2]') name2,
    json_value(x.obj, '$[3]') name4
from mytable t
cross apply (values('["' + replace(t.name, '_', '", "') + '"]')) x(obj)
诀窍是操纵字符串使其看起来像一个JSON数组(这就是
交叉应用
子查询所做的)。基本上,这将像
'a_B_C'
这样的字符串转换为
'[“a”,“B”,“C”]
。然后,我们可以使用
json\u value()
轻松访问每个元素

这并不假设元素是唯一的。实际上,唯一的要求是字符串不应包含嵌入的双引号

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 名称|名称1 |名称2 |名称2 |名称4 :------------- | :---- | :---- | :---- | :---- ABC|u DEFG|u HIJKL | ABC | DEFG | HIJKL |空 A|B|C | A | B | C |空 A|B|C|D|A | B | C | D
您也可以使用
PARSENAME()
作为:

SELECT Val,
       PARSENAME(Value, 1) Name1,
       PARSENAME(Value, 2) Name2,
       PARSENAME(Value, 3) Name3,
       PARSENAME(Value, 4) Name4
FROM
(
  VALUES
  ('ABC_DEFG_HIJKL'), 
  ('A_B_C'),
  ('A_B_C_D')
) T(Val) CROSS APPLY (VALUES(REPLACE(Val, '_', '.'))) TT(Value);
请注意,如果您有3个以上的
'.'
,则此项不起作用