Sql server 如何在T-SQL中清除字符串和提取数字后缀

Sql server 如何在T-SQL中清除字符串和提取数字后缀,sql-server,regex,tsql,Sql Server,Regex,Tsql,我有一个由名字组成的字符串,在大多数情况下,它有一个后缀,结尾有一个或两个数字。这个数字后缀应该从名称中删除。一个数字代表一种状态,应该提取。如果有两个数字,则是右边的第二个数字;如果有一个数字,则是右边的第一个数字。这些数字用下划线分隔。下划线也可以在名称中使用。 结果应该是一列,其中包含clearname和提取状态 我试图用标准字符串函数来解决这个问题,比如Substring、Charindex、Patindex、LEN和son等。但我的方法很快变得非常笨重,难以维护。我想知道是否有一个优雅

我有一个由名字组成的字符串,在大多数情况下,它有一个后缀,结尾有一个或两个数字。这个数字后缀应该从名称中删除。一个数字代表一种状态,应该提取。如果有两个数字,则是右边的第二个数字;如果有一个数字,则是右边的第一个数字。这些数字用下划线分隔。下划线也可以在名称中使用。 结果应该是一列,其中包含clearname和提取状态

我试图用标准字符串函数来解决这个问题,比如Substring、Charindex、Patindex、LEN和son等。但我的方法很快变得非常笨重,难以维护。我想知道是否有一个优雅的解决方案,如果可能的话,不需要为regex安装额外的SQl Server功能

SELECT _data.myStr
    -- , ... AS clearname  /*String cleaned from number_postfixes*/
    -- , ... AS Status     /*second number from the right*/
FROM (
    SELECT 'tree_leafs_offer_2_1' AS myStr  --clearname: tree_leafs_offer; cut off: _2_1; extracted status: 2
        UNION
    SELECT 'tree_leafs_offer_2_10' AS myStr --clearname: tree_leafs_offer_2_10; cut off: _2_10; extracted status: 2
        UNION
    SELECT 'tree_leafs_offer_2_2' AS myStr  --clearname: tree_leafs_offer; cut off: _2_2; extracted status: 2
        UNION
    SELECT 'tree_leafs_offer_1150_1' AS myStr   --clearname: tree_leafs_offer; cut off: _1150_1; extracted status: 1150
        UNION
    SELECT 'tree_leafs_offer_1150_10' AS myStr  --clearname: tree_leafs_offer; cut off: _1150_10; extracted status: 1150
        UNION
    SELECT 'builder_bundle_less_xl_1' AS myStr  --clearname: builder_bundle_less_xl; cut off: _1; extracted status: 1
        UNION
    SELECT 'builder_bundle_less_xl_10' AS myStr --clearname: builder_bundle_less_xl; cut off: _10; extracted status: 10
        UNION
    SELECT 'static_components_wolves_10_4' AS myStr --clearname: static_components_wolves; cut off: _10_4; extracted status: 4
        UNION
    SELECT 'coke_0_boring_components_bundle_grant_1' AS myStr   --clearname: oke_0_boring_components_bundle_grant; cut off: _1; extracted status: 1
        UNION
    SELECT 'coke_0_soccer18_end_1_4h_101' AS myStr  --clearname: coke_0_soccer18_end_1_4h; cut off: _101; extracted status: 101
        UNION
    SELECT 'coke_0_late_downsell_bundle_high_114' AS myStr  --clearname: coke_0_late_downsell_bundle_high; cut off: _114; extracted status: 114
        UNION
    SELECT 'itembundle_mine_bundle_small' AS myStr  --clearname: itembundle_mine_bundle_small; cut off: <nothing>; extracted status: NULL
) AS _data

老实说:这种格式太糟糕了!如果这不是一次性的行动,你真的应该在处理它之前尝试改变它

但是-如果你必须坚持这一点-你可以尝试一下:

编辑:解决了状态位置的错误计算

声明@tbl TABLEID INT-IDENTITY,myStr VARCHAR1000; 插入@tbl值 “树叶提供2个1” “树叶”提供2个10个 ,“树的叶子提供2” ,“树木叶子提供”1150“1” ,“树叶提供1150\u10” “建筑商、捆绑商、无捆绑商、xl、1” “建筑商、捆绑商、无捆绑商、xl、10” ,“静态组件\u狼群\u 10\u 4” “焦炭、0、钻孔、部件、捆绑、赠款、1” “可口可乐俱乐部18号俱乐部1号俱乐部4号俱乐部101” “可口可乐0晚销售捆绑销售高销售114” “项目包、矿山包、小型包”; 询问

以cte为例 选择t.ID ,t.myStr ,一个[键]作为位置 ,一个[value]作为WordFragment ,B.铸造点 来自@tbl t 交叉应用OPENJSONN'['+REPLACEt.myStr,''''','+']A 交叉应用程序选择TRY_CASTA.[value]作为INT bcastedpoint 选择ID ,myStr 东西 选择CONCAT'',cte2.WordFragment 来自cte cte2 其中cte2.ID=cte.ID
和cte2.Position老实说:这种格式太糟糕了!如果这不是一次性的行动,你真的应该在处理它之前尝试改变它

但是-如果你必须坚持这一点-你可以尝试一下:

编辑:解决了状态位置的错误计算

声明@tbl TABLEID INT-IDENTITY,myStr VARCHAR1000; 插入@tbl值 “树叶提供2个1” “树叶”提供2个10个 ,“树的叶子提供2” ,“树木叶子提供”1150“1” ,“树叶提供1150\u10” “建筑商、捆绑商、无捆绑商、xl、1” “建筑商、捆绑商、无捆绑商、xl、10” ,“静态组件\u狼群\u 10\u 4” “焦炭、0、钻孔、部件、捆绑、赠款、1” “可口可乐俱乐部18号俱乐部1号俱乐部4号俱乐部101” “可口可乐0晚销售捆绑销售高销售114” “项目包、矿山包、小型包”; 询问

以cte为例 选择t.ID ,t.myStr ,一个[键]作为位置 ,一个[value]作为WordFragment ,B.铸造点 来自@tbl t 交叉应用OPENJSONN'['+REPLACEt.myStr,''''','+']A 交叉应用程序选择TRY_CASTA.[value]作为INT bcastedpoint 选择ID ,myStr 东西 选择CONCAT'',cte2.WordFragment 来自cte cte2 其中cte2.ID=cte.ID
和cte2.Position一种可能的方法是使用SQL Server 2016+的字符串替换和JSON功能。每一行被反转并转换为一个有效的JSON数组。例如,“tree_leafs_offer_2_1”被转换为“[1,2,reffo,sfael,eert]”。然后,您可以使用JSON_值“$[0]”、JSON_值“$[1]”轻松检查第一项和第二项是否为有效数字,并尝试进行转换。如果您从右侧最多有两个数字,则此选项将起作用

输入:

CREATE TABLE #Data (
   myStr varchar(max)
)
INSERT INTO #Data 
   (MyStr)
VALUES   
   ('tree_leafs_offer_2_1'),
   ('tree_leafs_offer_2_10'),
   ('tree_leafs_offer_2_2'),
   ('tree_leafs_offer_1150_1'),
   ('tree_leafs_offer_1150_10'),
   ('builder_bundle_less_xl_1'),
   ('builder_bundle_less_xl_10'),
   ('static_components_wolves_10_4'),
   ('coke_0_boring_components_bundle_grant_1'),
   ('coke_0_soccer18_end_1_4h_101'),
   ('coke_0_late_downsell_bundle_high_114'),
   ('itembundle_mine_bundle_small')
T-SQL:

SELECT 
   LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr))) as ClearName,
   REVERSE(LEFT(REVERSE(myStr), CHARINDEX('_', REVERSE(myStr)) - 1)) AS Status
FROM (
   SELECT 
      CASE 
         WHEN 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NULL
            THEN CONCAT(myStr, '_0') 
         WHEN 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NOT NULL
            THEN MyStr 
         ELSE LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr)))
      END AS myStr      
   FROM #Data
) fixed
ORDER BY MyStr
输出:

----------------------------------------------
ClearName                               Status
----------------------------------------------
builder_bundle_less_xl                  1
builder_bundle_less_xl                  10
coke_0_boring_components_bundle_grant   1
coke_0_late_downsell_bundle_high        114
coke_0_soccer18_end_1_4h                101
itembundle_mine_bundle_small            0
static_components_wolves                10
tree_leafs_offer                        1150
tree_leafs_offer                        1150
tree_leafs_offer                        2
tree_leafs_offer                        2
tree_leafs_offer                        2

一种可能的方法是使用SQL Server 2016+的字符串替换和JSON功能。每一行被反转并转换为一个有效的JSON数组。例如,“tree_leafs_offer_2_1”被转换为“[1,2,reffo,sfael,eert]”。然后,您可以使用JSON_值“$[0]”、JSON_值“$[1]”轻松检查第一项和第二项是否为有效数字,并尝试进行转换。如果您从右侧最多有两个数字,则此选项将起作用

输入:

CREATE TABLE #Data (
   myStr varchar(max)
)
INSERT INTO #Data 
   (MyStr)
VALUES   
   ('tree_leafs_offer_2_1'),
   ('tree_leafs_offer_2_10'),
   ('tree_leafs_offer_2_2'),
   ('tree_leafs_offer_1150_1'),
   ('tree_leafs_offer_1150_10'),
   ('builder_bundle_less_xl_1'),
   ('builder_bundle_less_xl_10'),
   ('static_components_wolves_10_4'),
   ('coke_0_boring_components_bundle_grant_1'),
   ('coke_0_soccer18_end_1_4h_101'),
   ('coke_0_late_downsell_bundle_high_114'),
   ('itembundle_mine_bundle_small')
T-SQL:

SELECT 
   LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr))) as ClearName,
   REVERSE(LEFT(REVERSE(myStr), CHARINDEX('_', REVERSE(myStr)) - 1)) AS Status
FROM (
   SELECT 
      CASE 
         WHEN 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NULL
            THEN CONCAT(myStr, '_0') 
         WHEN 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[1]'))) IS NULL AND 
            TRY_CONVERT(int, REVERSE(JSON_VALUE(CONCAT('["', REPLACE(STRING_ESCAPE(REVERSE(MyStr), 'json'), '_', '","'), '"]'), '$[0]'))) IS NOT NULL
            THEN MyStr 
         ELSE LEFT(myStr, LEN(myStr) - CHARINDEX('_', REVERSE(myStr)))
      END AS myStr      
   FROM #Data
) fixed
ORDER BY MyStr
输出:

----------------------------------------------
ClearName                               Status
----------------------------------------------
builder_bundle_less_xl                  1
builder_bundle_less_xl                  10
coke_0_boring_components_bundle_grant   1
coke_0_late_downsell_bundle_high        114
coke_0_soccer18_end_1_4h                101
itembundle_mine_bundle_small            0
static_components_wolves                10
tree_leafs_offer                        1150
tree_leafs_offer                        1150
tree_leafs_offer                        2
tree_leafs_offer                        2
tree_leafs_offer                        2

这是一次性任务吗?您的SQL Server版本是什么?它是SQL Server 2016。它不是一次性任务,它将是定期运行的ETL过程的一部分。但它不是那么多的数据,所以性能不应该是一个大问题。Egad!!!当末尾有多个数字时,我才意识到您想要作为输出的数字。如果最后有三个连续的呢?四个怎么样?至少可以说,这些数据令人痛苦。您是否有可能更改此数据的来源,而不是被迫对此进行争论?这是一次性任务吗?您的SQL Server版本是什么?这是SQL Server 2016。这不是一次性任务,而是定期运行的ETL过程的一部分。但这并不是3500 r的太多数据
所以表现不应该是一个大问题。Egad!!!当末尾有多个数字时,我才意识到您想要作为输出的数字。如果最后有三个连续的呢?四个怎么样?至少可以说,这些数据令人痛苦。你是否有可能改变这些数据的来源,而不是被迫对此进行争论?除了解决方案的正确性,你最初的评论更重要+1从解决方案的实际情况来看,您最初的评论更为重要+1.