【问题标题】:SQL Server query using regex?使用正则表达式的 SQL Server 查询?
【发布时间】:2023-04-06 05:02:01
【问题描述】:

我在 SQL Server 数据库中有一个 varchar 字段,它以多种不同方式存储电话号码,但它们本质上都是电话号码。

例子:

8181234564
(818) 123 4564
818 - 123 - 4567

我希望我可以使用正则表达式去除所有非数字字符,然后在 .. 上执行类似或“=”,我可以这样做吗?

忘了说:我只有读权限。

【问题讨论】:

    标签: sql sql-server regex tsql


    【解决方案1】:

    如果您只有读取权限,您可能也无法创建函数。

    如果您可以创建一个函数,则可以使用一些现有的解决方案。如果不是,这很丑陋,但它适用于您的示例:

    declare @string varchar(50)
    set @string = '(818) 123 -  4564'
    
    select replace(replace(replace(replace(@string,'(',''),' ',''),')',''),'-','')
    

    【讨论】:

      【解决方案2】:

      如果您知道该字段包含某种有效形式的电话号码,那么以下非常丑陋的 LIKE 用法将匹配特定号码。查找 818-123-4567:

      select * from thetable where phonenum like ('%8%1%8%1%2%3%4%5%6%7%')
      

      当然,这也会匹配无效条目(例如,具有额外数​​字、字符等的数字)。而且它可能是一个相当昂贵的查询,无法使用任何索引。

      更现实的版本可能是这样的:

      select * from thetable where phonenum like ('%818%123%4567%')
      

      【讨论】:

        【解决方案3】:

        这里有一个类似的问题,有你的答案:

        How to strip all non-alphabetic characters from string in SQL Server?

        其中一个答案显示了如何从字符串中去除除数字之外的所有内容。基本上,您将创建一个 UDF 并使用正则表达式来清除您的非数字字符。然后你就可以进行比较了。

        【讨论】:

          【解决方案4】:

          这类事情最好在 CLR 或应用程序中做。但是如果你强烈需要在 TSQL 中这样做,那么这里有一个例子:

             DECLARE @D TABLE ( s NVARCHAR(1000), id INT )
          INSERT  INTO @D
                  ( s, id )
          VALUES  ( '8181234$564', 1 ),
                  ( '(818) 123 %&%%4564', 2 ),
                  ( '818 - 123 - 4567', 3 ) ;
          WITH    c ( s, Char, pos, id, Out )
                    AS ( SELECT   d.s ,
                                  SUBSTRING(d.s, 1, 1) ,
                                  CAST(1 AS BIGINT) ,
                                  d.id ,
                                  CASE WHEN SUBSTRING(d.s, 1, 1) IN ( '1', '2', '3', '4',
                                                                      '5', '6', '7', '8',
                                                                      '9', '0' )
                                       THEN CAST(SUBSTRING(d.s, 1, 1) AS NVARCHAR)
                                       ELSE ''
                                  END
                         FROM     @d D
                         UNION ALL
                         SELECT   d.s ,
                                  SUBSTRING(d.s, c.pos + 1, 1) ,
                                  c.pos + 1 ,
                                  d.id ,
                                  CASE WHEN SUBSTRING(d.s, c.pos + 1, 1) IN ( '1', '2',
                                                                        '3', '4', '5',
                                                                        '6', '7', '8',
                                                                        '9', '0' )
                                       THEN CAST(c.Out + SUBSTRING(d.s, c.pos + 1, 1) AS NVARCHAR)
                                       ELSE c.Out
                                  END
                         FROM     @d D
                                  JOIN C ON c.id = d.id
                         WHERE    c.pos < LEN(c.s)
                       )
              SELECT  c.s [In] ,
                      c.Out
              FROM    c
                      JOIN ( SELECT   MAX(c2.pos) MaxPos ,
                                      s
                             FROM     c C2
                             GROUP BY C2.s
                           ) CC ON cc.s = c.s
                                   AND c.pos = cc.MaxPos
          

          【讨论】:

          • 太棒了。我将分叉版本并针对内联表函数进行一些修改。当我有机会完成它的时候会发布。感谢分享!
          【解决方案5】:

          很遗憾,我还没有找到这个帖子;在 VBA 中有解决方案并将其修改为 SQL 格式。下面是如何创建函数和如何使用的示例。让管理员添加功能最快捷的解决问题的方法。

          我使用一个功能来清理电话号码,这将解决所有电话号码问题或清除该字段。如果为空则返回 Null(以防止错误)

          Print'/*Fix Phone Numbers Call*/'
          Update tblTemp
              Set Phone = dbo.fnPhoneFix(tblTemp.Phone)
          From tblTemp
          

          要创建函数,请使用以下代码:

          CREATE FUNCTION [dbo].[fnPhoneFix](@PhoneOld VarChar(20))
              Returns VarChar(10)
          AS
              Begin
              Declare @iCnt Int = 0
              Declare @PhoneNew VarChar(15)  = ''
          
              IF @PhoneOld IS NULL
                  RETURN NULL;
          
              While @iCnt <= LEN(@PhoneOld)
                  Begin
                      IF Substring(@PhoneOld,@iCnt,1) >= '0' AND Substring(@PhoneOld,@iCnt,1) <= '9'
                      Begin
                          SET @PhoneNew = @PhoneNew + Substring(@PhoneOld,@iCnt,1)
                      End
                      Set @iCnt = @iCnt + 1
                  End
          
              If LEN(@PhoneNew) > 10 and Left(@PhoneNew, 1) = '1'
                  Set @PhoneNew = RIGHT(@PhoneNew,10);
              Else
                  Set @PhoneNew = Left(@PhoneNew,10);
          
              Return @PhoneNew
          End
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-06-18
            • 1970-01-01
            • 2015-12-20
            • 1970-01-01
            • 2012-11-06
            • 1970-01-01
            • 2017-05-13
            相关资源
            最近更新 更多