【问题标题】:What is regexp_replace equivalent in SQL ServerSQL Server 中的 regexp_replace 等价物是什么
【发布时间】:2020-08-12 18:05:44
【问题描述】:

我在 Oracle 中有这段代码,我需要将其转换为 SQL Server 以获得相同的行为。我使用了REPLACE 函数。它似乎有效,但我只是想确定一下。

REGEXP_REPLACE(
                phonenumber, 
               '([[:digit:]]{3})([[:digit:]]{3})([[:digit:]]{4})', 
               '(\1)\2-\3'
               ) phonenumber

【问题讨论】:

  • SQL Server 中的 REPLACE 函数肯定不能解决这个问题
  • @MartinSmith 任何建议
  • 所以您正在寻找精确匹配 10 位数字的字符串并尝试将它们转换为 (012)345-6789?
  • 如果您需要在 SQL Server 中实际支持 REGEX,则需要实现 CLR 函数。
  • 是的,没错。所以基本上,例如,我有电话号码 xxx- xxx xxxx,我想将其格式化为 (xxx) xxx- xxxx

标签: sql-server regex oracle


【解决方案1】:

SQL Server 不支持本机正则表达式。您将需要使用 CLR(或 @Lukasz Szozda 在 cmets 中指出较新的 Language Extensions 之一)。

如果我正确理解了正则表达式,尽管它匹配 10 位数字的字符串并将前 3 个分配给第 1 组,第二个 3 分配给第 2 组,最后 4 个分配给第 3 组,然后在表达式 (\1)\2-\3 中使用反向引用

您可以使用内置的字符串函数来执行此操作,如下所示

SELECT CASE
         WHEN phonenumber LIKE REPLICATE('[0-9]', 10)
           THEN  FORMATMESSAGE('(%s)%s-%s', 
                      LEFT(phonenumber, 3),
                      SUBSTRING(phonenumber, 4, 3),
                      RIGHT(phonenumber, 4))
         ELSE phonenumber
       END

【讨论】:

  • 仍然是 CLR?现在当我们支持Java/R/Python "This extends the TSQL surface area to better handle use cases involving regular expressions, string handling, and NLP support."
  • 是的,没错,CLR/其他语言扩展 - 仍然没有任何可用的东西,无需编写自定义代码并可能启用当前禁用的其他功能
【解决方案2】:

您可以使用 CLR 编写 SQL 函数,该函数将包装标准 dotnet 正则表达式。我已经写了这个,你可以使用它there。它看起来像这样:

DECLARE @SourceText NVARCHAR(MAX) = N'My first line <br /> My second line';
DECLARE @RegexPattern NVARCHAR(MAX) = N'([<]br\s*/[>])';
DECLARE @Replacement NVARCHAR(MAX) = N''
DECLARE @IsCaseSensitive BIT = 0;

SELECT regex.Replace(@SourceText, @RegexPattern, @Replacement, @IsCaseSensitive);

【讨论】:

  • 考虑到该链接指向一个“废旧的 CoCo”Github 存储库,您应该注意到它是您编写的。
【解决方案3】:

正如 Martin 在 his answer 中所说,SQL Server 没有内置的 RegEx 功能(虽然这里没有建议,但要明确一点:不,LIKE 和 @987654329 的 [...] 通配符@ 是 不是 正则表达式)。如果您的数据几乎没有变化,那么可以,您可以使用一些 T-SQL 函数组合:REPLACESUBSTRINGLEFTRIGHTCHARINDEXPATINDEXFORMATMESSAGECONCAT,也许还有一两个人。

但是,如果数据/输入甚至具有中等程度的复杂性,那么内置的 T-SQL 函数充其量是繁琐的,最坏的情况是无用的。在这种情况下,可以通过 SQLCLR 执行实际的 RegEx(只要您不使用 Azure SQL Database Single DB 或通过 AWS RDS 使用 SQL Server 2017+),这是在 SQL Server 中运行的(受限).NET 代码。您可以编写自己的代码/在 S.O. 上找到示例。或其他地方,或尝试一个预先完成的库,例如我创建的SQL# (SQLsharp),它的免费版本包含几个 RegEx 函数。请注意,作为 .NET 的 SQLCLR 不是基于 POSIX 的 RegEx,因此不使用 POSIX character classes(意思是:您需要将 \d 用于“数字”而不是 [:digit:])。

在这种特殊情况下所需的复杂程度尚不清楚,因为问题中的示例代码暗示数据简单且统一(即1112223333),但comment on the question 中显示的示例数据似乎表明存在可能是数据中的破折号和/或空格(即xxx- xxx xxxx)。

如果数据确实是统一的,那就坚持使用@MartinSmith 提供的纯T-SQL 解决方案。但是,如果数据足够复杂,那么请考虑下面的 RegEx 示例,使用我的SQL# 库的免费版本中的 SQLCLR 函数(如前所述),它可以轻松处理输入数据的 3 种变化等等:

SELECT SQL#.RegEx_Replace4k(tmp.phone,
                            N'\(?(\d{3})\)?[ .-]*(\d{3})[ .-]*(\d{4})', N'($1)$2-$3',
                            -1,   -- count (-1 == unlimited)
                            1,    -- start at
                            N'')  -- RegEx options
FROM   (VALUES (N'8885551212'),
               (N'123- 456 7890'),
               (N'(777) 555- 4653')
       ) tmp([phone]);

返回:

(888)555-1212
(123)456-7890
(777)555-4653

RegEx 模式允许:

  • 0 或 1 (
  • 3 个十进制数字
  • 0 或 1 )
  • 0 个或多个 .-
  • 3 个十进制数字
  • 0 个或多个 .-
  • 4 位十进制数字

注意

有人提到较新的语言扩展可能是比 SQLCLR 更好的选择。语言扩展允许通过sp_execute_external_script 存储过程调用托管在 SQL Server 之外的 R / Python / Java 代码。正如Tutorial: Search for a string using regular expressions (regex) in Java 页面所示,外部脚本实际上不是SQL Server 中RegEx 的许多/大多数用途的好选择。主要问题是:

  1. 与 SQLCLR 不同,外部脚本的唯一接口是存储过程。这意味着您不能在查询中使用任何内联功能(SELECTWHERE 等)。
  2. 使用外部脚本,您可以传入查询,使用外部语言处理结果,然后传回静态结果集。这意味着编译后的代码现在必须更专业(即紧密耦合)到特定用途。更改查询使用 RegEx 的方式和/或返回的列现在需要编辑、编译、测试和部署 R / Python / Java 代码以及(协调!)T-SQL变化。

我确信外部脚本绝对很棒,并且在某些情况下是比 SQLCLR 更好的选择。但它们当然不适合 RegEx 的使用方式(与许多/大多数其他功能一样)的高度多样化且通常是临时性的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多