【问题标题】:SQL Split String on Delimiter and set to new columns分隔符上的 SQL 拆分字符串并设置为新列
【发布时间】:2017-08-18 16:55:12
【问题描述】:

有人提出了与此相关的问题,但我没有得到我需要的解决方案。

我尝试拆分的字符串如下所示:

/Dev/act/billing

/ST/recManage/prod/form

我遇到的问题是,当我尝试使用 LEFT/RIGHT/SUBSTRING/CHARINDEX 执行操作时,第一个“/”给我带来了问题。它弄乱了计数并在分隔符处停止。此外,重要的是要注意分隔符的数量会发生变化。所以我想找到一种方法来拆分它,这样我就可以获得所有可能的子字符串。

RIGHT(c3.Path,CHARINDEX('/', REVERSE(c3.Path))-1) AS LastPath

这让我得到了字符串的最后一部分。我把其他事情搞砸了:

SUBSTRING(c3.Path,CHARINDEX('/',c3.Path,(CHARINDEX('/',c3.Path)+1))+1,len(c3.Path)),

这会得到第二个'/'之后的所有内容

我也弄乱了 XML 和

SET @delimiter='/' 
;WITH CTE AS

(SELECT CAST('<M>' + REPLACE([Path], @delimiter , '</M><M>') + '</M>' AS XML) 
        AS [Type XML]


FROM  [Rpts].[dbo].[Cata] 
)
, 

CTE2 as (Select [Type XML].value('/M[2]', 'varchar(50)') As FirstPath from CTE)

然后做: CTE2.FirstPath 得到结果。但这会给出 NULL

我不在 SQL 2016 上,所以我不能使用 SPLIT_STRING。

谢谢

【问题讨论】:

  • 是否需要将每个值拆分并放入行中?

标签: sql sql-server tsql


【解决方案1】:

试试这个:

DECLARE @mockup TABLE(ID INT IDENTITY,YourString VARCHAR(MAX));
INSERT INTO @mockup VALUES('/Dev/act/billing'),('/ST/recManage/prod/form');

SELECT m.ID
      ,B.part.value(N'text()[1]',N'nvarchar(max)')
FROM @mockup AS m
OUTER APPLY(SELECT CAST('<x>' + REPLACE(m.YourString,'/','</x><x>')  + '</x>' AS XML)) AS A(Casted)
OUTER APPLY A.Casted.nodes(N'/x[text()]') AS B(part);

只要您的字符串中没有禁用字符(即&lt;&gt;&amp;),这种方法就可以保存。需要这个,打个电话,就可以解决。

使用.nodes()XQuery 谓词[text()] 将省略所有没有值的行...

结果

ID  Part
---------
1   Dev
1   act
1   billing
2   ST
2   recManage
2   prod
2   form

【讨论】:

  • 有趣的是,你避免了初始 null 没有任何字符串操作看起来更难看这个 +1
【解决方案2】:

如果没有动态,并且如果您的列数有限(或最大),可能是这样的:

Cross Apply 中的 replace() 假定字符串以 '/' 开头

(易于扩展或收缩......模式非常清晰)

示例

Declare @YourTable table (ID int,[Path] varchar(max))
Insert Into @YourTable values
 (1,'/Dev/act/billing')
,(2,'/ST/recManage/prod/form')

Select A.ID
      ,B.*
 From @YourTable A
 Cross Apply (
                Select Pos1 = xDim.value('/x[1]','varchar(max)')
                      ,Pos2 = xDim.value('/x[2]','varchar(max)')
                      ,Pos3 = xDim.value('/x[3]','varchar(max)')
                      ,Pos4 = xDim.value('/x[4]','varchar(max)')
                      ,Pos5 = xDim.value('/x[5]','varchar(max)')
                      ,Pos6 = xDim.value('/x[6]','varchar(max)')
                      ,Pos7 = xDim.value('/x[7]','varchar(max)')
                      ,Pos8 = xDim.value('/x[8]','varchar(max)')
                      ,Pos9 = xDim.value('/x[9]','varchar(max)')
                From  (Select Cast('<x>' + replace(substring(A.Path,2,len(A.Path)),'/','</x><x>')+'</x>' as xml) as xDim) as A 
             ) B

退货

编辑 - 略微简化的版本

注意 Pos1/x[2] 的滞后

Select A.ID
      ,Pos1 = xDim.value('/x[2]','varchar(max)')
      ,Pos2 = xDim.value('/x[3]','varchar(max)')
      ,Pos3 = xDim.value('/x[4]','varchar(max)')
      ,Pos4 = xDim.value('/x[5]','varchar(max)')
      ,Pos5 = xDim.value('/x[6]','varchar(max)')
 From @YourTable A
 Cross Apply ( Select Cast('<x>' + replace(A.Path,'/','</x><x>')+'</x>' as xml) ) B (xDim)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 2021-06-23
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多