【问题标题】:SQL - Get numbers from string after a pound (#) signSQL - 从井号 (#) 符号后的字符串中获取数字
【发布时间】:2017-09-12 14:52:11
【问题描述】:

我正在尝试从 SQL Server 2012 中位于井号 (#) 符号之后和后面的任何空格之前的字符串中获取数字。例如,商店号码。假设我们有以下内容:

Big Box Store #450
Big Box Store #768
Little Shop #2
Widgets Warehouse #678
Little Shop #5
Widgets Warehouse #559
Corner Boutiques #32 *CLOSED
Corner Boutiques #67 *CLOSED
Corner Boutiques #12
Buy More #1047 SUPERSTORE
1 Stop Shop #3
1 Stop Shop #17
You 2 Me #16

我会返回以下值:450、768、2、678、5、559、32、67、12、1047、3、17、16。

如您所见,并非所有字符串的末尾都有数字。其中一些甚至在商店名称中带有数字字符。我认为解决此问题的最佳方法是提取井号后面的数字。

有没有办法做到这一点?我看过以下文章:

Query to get only numbers from a string

https://www.sqlservercentral.com/Forums/Topic456023-338-1.aspx

似乎PATINDEX 可能很好用,但我不确定到目前为止我所尝试的方法并没有返回预期的结果。

非常感谢!

【问题讨论】:

    标签: sql sql-server patindex


    【解决方案1】:

    另一种类似的方式...使用来自Tyron 的测试数据。即使数字后没有空格,这也有效。

    DECLARE @t TABLE(
      MyString NVARCHAR(1000)
    );
    
    INSERT INTO @t VALUES 
     ('Big Box Store #450')
    ,('Big Box Store #768')
    ,('Little Shop #2')
    ,('Widgets Warehouse #678')
    ,('Little Shop #5')
    ,('Widgets Warehouse #559')
    ,('Corner Boutiques #32*CLOSED')    --notice no space here
    ,('Corner Boutiques #67 *CLOSED')
    ,('Corner Boutiques #12')
    ,('Buy More #1047 SUPERSTORE')
    ,('1 Stop Shop #3')
    ,('1 Stop Shop #17')
    ,('You 2 Me #16');
    
    select
        SUBSTRING(MyString,CHARINDEX('#',MyString,0) + 1,case when PATINDEX('%[^0-9]%',RIGHT(MyString,LEN(MyString) - CHARINDEX('#',MyString,0))) = 0 then 99 else PATINDEX('%[^0-9]%',RIGHT(MyString,LEN(MyString) - CHARINDEX('#',MyString,0))) - 1 end)
        --char version...
       ,SUBSTRING(MyString,CHARINDEX('#',MyString,0) + 1,case when PATINDEX('%[^0-9]%',substring(MyString,CHARINDEX('#',MyString,0) + 1,LEN(MyString) - CHARINDEX('#',MyString,0) + 1)) = 0 then 99 else PATINDEX('%[^0-9]%',substring(MyString,CHARINDEX('#',MyString,0) + 1,LEN(MyString) - CHARINDEX('#',MyString,0) + 1)) - 1 end)
    
    from
        @t
    

    【讨论】:

    • 这看起来很棒,我测试过它适用于数据集,但我的数据类型是 char(65)。您的解决方案似乎仅适用于 varchars 和 nvarchars。我做错了什么还是有其他方法?我什至加入了一些“CONVERT”函数来将它们转换为 varchar(65),但这不起作用。谢谢!
    • @jderekc 我添加了一个CHAR 版本。 RIGHT() 函数只接受 NVARCHARVARCHAR。我将其替换为 SUBSTRING
    • 这太完美了!每天学些新东西。非常感谢您的帮助,@scsimon。
    • 完全不用担心@jderekc
    【解决方案2】:

    不是很漂亮,但似乎满足您的要求。 ;-)

    DECLARE @t TABLE(
      MyString NVARCHAR(1000)
    );
    
    INSERT INTO @t VALUES 
     ('Big Box Store #450')
    ,('Big Box Store #768')
    ,('Little Shop #2')
    ,('Widgets Warehouse #678')
    ,('Little Shop #5')
    ,('Widgets Warehouse #559')
    ,('Corner Boutiques #32 *CLOSED')
    ,('Corner Boutiques #67 *CLOSED')
    ,('Corner Boutiques #12')
    ,('Buy More #1047 SUPERSTORE')
    ,('1 Stop Shop #3')
    ,('1 Stop Shop #17')
    ,('You 2 Me #16');
    
    SELECT  MyString
           ,SUBSTRING(MyString
                     ,CHARINDEX('#', MyString) + 1
                     ,CASE(CHARINDEX(' ', SUBSTRING(MyString
                                                   ,CHARINDEX('#', MyString) + 1
                                                   ,LEN(MyString) - CHARINDEX('#', MyString)
                                                   )
                                    )
                          )
                        WHEN 0 THEN LEN(MyString) - CHARINDEX('#', MyString)
                        ELSE CHARINDEX(' ', SUBSTRING(MyString
                                                     ,CHARINDEX('#', MyString) + 1
                                                     ,LEN(MyString) - CHARINDEX('#', MyString)
                                                     )
                                      ) - 1
                      END
                     ) AS MyNumber
      FROM @t
    

    【讨论】:

    • 虽然我确实发现有时商店会在没有编号的情况下列出,或者商店编号和“*CLOSED”标签之间没有空格,但正如 scsimon 预测的那样。但是我的数据类型是 char(65),它适用于您的解决方案,但由于某种原因不适用于 scsimon。谢谢!
    【解决方案3】:

    请尝试一下,使用路径索引

        DECLARE @TABLE AS TABLE(
    name_col varchar(250)
    )
    
    INSERT INTO @TABLE
    SELECT
    'Big Box Store #450' UNION ALL
    SELECT'Big Box Store #768'UNION ALL
    SELECT'Little Shop #2'UNION ALL
    SELECT'Widgets Warehouse #678'UNION ALL
    SELECT'Little Shop #5'UNION ALL
    SELECT'Widgets Warehouse #559'UNION ALL
    SELECT'Corner Boutiques #32 *CLOSED'UNION ALL
    SELECT'Corner Boutiques #67 *CLOSED'UNION ALL
    SELECT'Corner Boutiques #12'UNION ALL
    SELECT'Buy More #1047 SUPERSTORE'UNION ALL
    SELECT'1 Stop Shop #3 132132'UNION ALL
    SELECT'1 Stop Shop #17'UNION ALL
    SELECT'You 2 Me #16'
    
    SELECT 
    LEFT(SUBSTRING(
         SUBSTRING(name_col,CHARINDEX('#',name_col) + 1,LEN(name_col)), 
         PATINDEX('%[0-9.-]%',SUBSTRING(name_col,CHARINDEX('#',name_col) + 1,LEN(name_col))), 8000),
         PATINDEX('%[^0-9.-]%', SUBSTRING(SUBSTRING(name_col,CHARINDEX('#',name_col) + 1,LEN(name_col)), 
         PATINDEX('%[0-9.-]%', SUBSTRING(name_col,CHARINDEX('#',name_col) + 1,LEN(name_col))), 8000) + 'X') -1)
    
    FROM @TABLE
    

    您的怀疑是正确的,使用PATINDEX 是解决方案,请查看链接了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-09
      • 2015-03-24
      • 1970-01-01
      • 2018-02-12
      • 1970-01-01
      • 2022-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多