【问题标题】:How to parse a string with multiple underscores and dashes如何解析具有多个下划线和破折号的字符串
【发布时间】:2020-06-02 08:56:22
【问题描述】:

我需要一些指导并寻找更好的方法来解析字符串。

示例 1:

字符串:Automation_LOY_Loyalty_PC_CampaignName3-Abandoners-Email1_NoPromo_USA

CSV:自动化、LOY、忠诚度、PC、CampaignName3、Abandoners、Email1、NoPromo、美国

示例 2:

字符串:20200601_LOY_Functional_PC_CampaignName1_NoPromo_CAN

CSV:20200601,LOY,Functional,PC,CampaignName1,,,无促销,CAN

如您所见,有些字符串没有所有字段,所以有些 csv 字段需要留空。

现在我正在使用下面的这段代码,它非常混乱。除了像这样使用 CHARINDEX 之外,还有更好的方法来处理它吗?

SELECT [EmailName]
      -- Deployment Type
      ,CASE LEFT([EmailName], (CHARINDEX('_', [EmailName])) - 1)
        WHEN 'Automation' THEN 'Automation' 
        ELSE 'AdHoc' END AS [Deployment]
      -- Type
      ,SUBSTRING([EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1, CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1) + 1) - CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1) - 1) AS [Type]
      -- Customer_Type
      ,SUBSTRING([EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1) + 1) + 1, CHARINDEX('_', [EmailName],CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1)) - CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) - 1) AS [Customer_Type]
      -- Campaign_Name
      ,CASE WHEN (CHARINDEX('-', [EmailName])) = 0 THEN SUBSTRING([EmailName], (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1))) + 1, (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1)) + 1))) - (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1))) - 1)
            WHEN (CHARINDEX('-', [EmailName])) > 0 THEN SUBSTRING([EmailName], (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1))) + 1, ((CHARINDEX('-', [EmailName])) - (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1)))) - 1)
            ELSE NULL END AS [Campaign_Name]
      ,CASE WHEN (CHARINDEX('-', [EmailName])) = 0 THEN 1
            WHEN (CHARINDEX('-', [EmailName])) > 0 THEN REPLACE(SUBSTRING([EmailName], ((CHARINDEX('-', [EmailName])) + 1), (CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName])) + 1)) + 1) + 1)) + 1))) - (CHARINDEX('-', [EmailName])) - 1),'Email','')
            ELSE NULL END AS [Email_Num]
FROM TableName

【问题讨论】:

  • 我可以看到你的字符串的格式。你想要什么?示例数据和所需的结果很有帮助。
  • @GordonLinoff 抱歉,csv 所需的结果在那里,但它被格式化在同一行,所以很混乱。

标签: sql tsql


【解决方案1】:

另一种选择是一点点 XML

不清楚是否需要逗号分隔的字符串或单独的列

示例

Declare @YourTable Table ([ID] varchar(50),[SomeCol] varchar(150))
Insert Into @YourTable Values 
 (1,'Automation_LOY_Loyalty_PC_CampaignName3-Abandoners-Email1_NoPromo_USA')
,(2,'20200601_LOY_Functional_PC_CampaignName1_NoPromo_CAN')

Select A.ID 
      ,B.Pos1
      ,B.Pos2
      ,B.Pos3
      ,B.Pos4
      ,Pos5a = xmlData.value('/x[1]','varchar(max)')
      ,Pos5b = xmlData.value('/x[2]','varchar(max)')
      ,Pos5c = xmlData.value('/x[3]','varchar(max)')
      ,B.Pos6
      ,B.Pos7
 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)')
                From  ( values (cast('<x>' + replace((Select replace(SomeCol,'_','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml)))  A(xDim)
             ) B
 Cross Apply ( values (cast('<x>' + replace((Select replace(Pos5,'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) ) ) C(xmlData)

退货

【讨论】:

  • @user3276533 总是乐于提供帮助
【解决方案2】:

我不会完全回答这个问题,但无论如何都会给你一些线索。在 SQL Server 中,您可以使用 STRING_SPLIT 函数来拆分字符串。但它只接受一个分隔符。由于您似乎想在连字符 (-) 和下划线 (_) 上进行拆分,您可以做的是:

  • 将所有出现的连字符替换为下划线
  • 然后拆分字符串

例子:

declare @str varchar(500)
set @str = 'Automation_LOY_Loyalty_PC_CampaignName3-Abandoners-Email1_NoPromo_USA'
set @str = REPLACE(@str, '-', '_')

SELECT 
    value  
FROM 
    STRING_SPLIT(@str,'_')

结果(9 行):

自动化 洛伊 忠诚 个人电脑 活动名称3 遗弃者 电子邮件1 无促销 美国

问题在于第二个字符串:20200601_LOY_Functional_PC_CampaignName1_NoPromo_CAN。

结果(7 行):

20200601 洛伊 功能性 个人电脑 活动名称1 无促销 能够

没有简单的方法来判断缺少哪些字段。如果每个空白字段有一个“占位符”下划线,我们可以计算它们,但这里不是这种情况。也许你可以设计一个规则。但我不确定 SQL 是否是答案。也许您应该尝试使用 Powershell 之类的脚本语言来拆分字符串,查看模式并找出存在/缺失的字段。

【讨论】:

  • 谢谢,但我正在寻找一种方法来解析列中的名称,而不是行中。
  • 这是一个开始。您可以将行转换回列(枢轴或其他)。或者实际上您可以使用两次replace 将连字符和下划线转换为逗号。但这并不能解决更大的问题:缺少字段。我不知道如何确定。
  • 我唯一遇到的问题是 string_split() 不能保证顺序。
  • 然后放弃这个想法。相反,您可以:set @str = REPLACE(REPLACE(@str, '-', '_'), '_', ',') 并且您有一个 CSV 字符串。只需将每个连字符或下划线替换为逗号即可。
【解决方案3】:

我找到了 STRING_SPLIT 和 PARSENAME,但它们没有帮助。经过一番思考,我预先计算了子查询中的索引。

SELECT
    x.[EmailName]
    ,CASE 
        WHEN LEFT(x.[EmailName], Underscore_One - 1) = 'Automation' THEN 'Automation'
        WHEN LEFT(x.[EmailName], Underscore_One - 1) LIKE '[1-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9]' THEN 'Adhoc'
        ELSE NULL END AS [Deployment]
    ,SUBSTRING(x.[EmailName],Underscore_One + 1, Underscore_Two - Underscore_One - 1) AS [BU]
    ,SUBSTRING(x.[EmailName],Underscore_Two + 1, Underscore_Three - Underscore_Two - 1) AS [Type]
    ,SUBSTRING(x.[EmailName],Underscore_Three + 1, Underscore_Four - Underscore_Three - 1)  AS [Customer_Type]
    ,CASE WHEN x.Dash_Nums = 0 THEN SUBSTRING(x.[EmailName],Underscore_Four + 1, Underscore_Five - Underscore_Four - 1) 
        WHEN x.Dash_Nums > 0 THEN SUBSTRING(x.[EmailName], Underscore_Four + 1, Dash_One - Underscore_Four - 1) 
        ELSE NULL END AS [Campaign_Name]
    ,CASE WHEN x.Dash_Nums = 1 AND SUBSTRING(x.[EmailName], Dash_One + 1, Underscore_Five - Dash_One - 1) LIKE 'Email[0-9]%' THEN REPLACE(SUBSTRING(x.[EmailName], Dash_One + 1, Underscore_Five - Dash_One - 1),'Email','')
        WHEN x.Dash_Nums = 2 THEN REPLACE(SUBSTRING(x.[EmailName], Dash_Two + 1, Underscore_Five - Dash_Two - 1),'Email','')
        ELSE NULL END AS [Email_Num]
    ,CASE WHEN x.Dash_Nums = 2 THEN REPLACE(SUBSTRING(x.[EmailName], Dash_One + 1, Dash_Two - Dash_One - 1),'Email','')
        ELSE NULL END AS [Segment]
    ,CASE SUBSTRING(x.[EmailName],Underscore_Five + 1, Underscore_Six - Underscore_Five - 1)
        WHEN 'Promo' THEN 'Y'
        WHEN 'NoPromo' THEN 'N'
        ELSE NULL END AS [Promo_Flag]

FROM (SELECT [EmailName]
    ,LEN([EmailName]) - LEN(REPLACE([EmailName],'_','')) AS Underscore_Nums
      ,CHARINDEX('_', [EmailName]) AS Underscore_One
      ,CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) AS Underscore_Two
      ,CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) + 1)) AS Underscore_Three
      ,CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) + 1))) + 1)) AS Underscore_Four
      ,CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) + 1))) + 1)) + 1)) AS Underscore_Five
      ,CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) + 1))) + 1)) + 1)) + 1)) AS Underscore_Six
      ,CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName], (CHARINDEX('_', [EmailName], ((CHARINDEX('_', [EmailName])) + 1)) + 1))) + 1)) + 1)) + 1)) + 1)) AS Underscore_Seven
      ,LEN([EmailName]) - LEN(REPLACE([EmailName],'-','')) AS Dash_Nums
      ,CHARINDEX('-', [EmailName]) AS Dash_One
      ,CHARINDEX('-', [EmailName], (CHARINDEX('-', [EmailName])  + 1)) AS Dash_Two
      ,CHARINDEX('-', [EmailName], (CHARINDEX('-', [EmailName], (CHARINDEX('-', [EmailName])  + 1)) + 1)) AS Dash_Three
      -- Substring(Col, Start Index + 1, End Index - 1)
  FROM [minyoung].[dbo].[Consumer_Marketing_EmailName20200601]
    WHERE Campaign_Name = '') AS x

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 2011-08-29
    • 2016-06-29
    • 2019-05-15
    • 1970-01-01
    相关资源
    最近更新 更多