如何在 SQL 函数 CHARINDEX 中使用 RegEx 查找第 n 次出现

Posted

技术标签:

【中文标题】如何在 SQL 函数 CHARINDEX 中使用 RegEx 查找第 n 次出现【英文标题】:How to use RegEx in the SQL function CHARINDEX to find the nth occurrence 【发布时间】:2019-08-29 18:30:16 【问题描述】:

以下算法的目的是从键中提取某些字段集(在本示例中,提取前 2 个字段),并且它有效。字段由冒号分隔:

declare @key nvarchar (max);
declare @pos int;
declare @fields nvarchar (max);

set @key = 'Field-1:Field-2:Field-3:Field-4:Field-5';
set @pos = charindex(':', @key, charindex (':', @key) + 1);
set @fields = left(@key, @pos - 1);

select @fields;

结果:Field-1:Field-2

Microsoft document 说第一个参数是一个表达式,但我认为他们在 CHARINDEX 上下文中的意思是,这个表达式应该计算为字符串文字;因此,以下尝试通过正则表达式来获得第二次出现不起作用;显然要么不支持,要么我使用了错误的语法:

--match the second occurrence of the delimiter using RegEx
set @pos = charindex (':.*?(:)', @key);

换句话说,是否可以使用 RegEx 找到给定文本中第 n 次出现分隔符的位置,这样我就可以避免多个嵌套的 CHARINDEX 或循环解析?顺便说一句,如果 n 作为参数传递,那么我什至不能再使用静态嵌套了...

提前感谢您的帮助。

环境:Microsoft SQL Server 2014 (SP3) 标准版(64 位)

【问题讨论】:

您想要第 n 个子字符串或直到第 n 个分隔符的所有内容? PATINDEX docs.microsoft.com/en-us/sql/t-sql/functions/… 支持模式搜索。没有 Sql-server 功能支持 RegEx。 @SalmanA 直到第 n 个分隔符为止的所有内容 SQL Server 不擅长这个。您可以使用 rCTE。或者将字符串转换为 XML,找到直到第 n 个节点的所有节点并使用 STRING_AGG 函数重新梳理。无论您使用哪种方法都是笨拙的。 @SalmanA 谢谢。 2016 有 STRING_SPLIT,不幸的是我用的是 2014! 【参考方案1】:

没有简单的方法,只有技巧,可以提取字符串的第 n 个子字符串。下面是一个基于集合的递归 CTE 方法:

DECLARE @str NVARCHAR(MAX) = N'Field-1:Field-2:Field-3:Field-4:Field-5';
DECLARE @num INT = 4;

WITH rcte AS (
    SELECT str = @str
         , n = 1
         , p = CHARINDEX(':', @str, 1)
    UNION ALL
    SELECT str
         , n + 1
         , CHARINDEX(':', str, p + 1)
    FROM rcte
    WHERE n < @num AND p > 0
)
SELECT CASE WHEN p > 0 THEN SUBSTRING(str, 1, p - 1) ELSE str END
FROM rcte
WHERE n = @num;

如果循环是一个选项,那么:

DECLARE @str NVARCHAR(MAX) = N'Field-1:Field-2:Field-3:Field-4:Field-5';
DECLARE @num INT = 4;
DECLARE @n INT = 0;
DECLARE @p INT = 0;

WHILE 1 = 1
BEGIN
    SET @n = @n + 1;
    SET @p = CHARINDEX(':', @str, @p + 1);
    IF @n = @num OR @p = 0 BREAK;
END;

SELECT CASE WHEN @p > 0 THEN SUBSTRING(@str, 1, @p - 1) ELSE @str END;

DB<>Fiddle

【讨论】:

非常欣赏;将探索 CTE 方法。【参考方案2】:

请注意,我在字符串末尾添加了“:”。如有必要,请进行调整。

declare @n int = 5
declare @i int = 0
declare @len int = 0
declare @pos int = 0
declare @c char(1) = ":"
declare @str varchar(256)

set @str = "Field-1:Field-2:Field-3:Field-4:Field-5:"
set @len = len(@str)

while(@i < @n and @pos < @len)
begin
    set @pos = charindex(@c, @str, @pos + 1)
    set @i = @i + 1
end

select substring(@str, 1, @pos -1)

【讨论】:

感谢您的建议,但这假设所有字段的大小都相同...我更改了一个字段的大小,但算法失败了! @Noble 这并不假定所有字段都具有相同的大小。唯一的假设是字段由“:”分隔。 我改变了第3个字段,如下图,结果出来了: set @str = 'Field-1:Field-2:Fields-3:Field-4:Field-5:'结果:Field-1:Field-2:Fields-3:Field-4:Field- @Noble 谢谢你指出。我做了必要的更正。我还添加了一条注释。

以上是关于如何在 SQL 函数 CHARINDEX 中使用 RegEx 查找第 n 次出现的主要内容,如果未能解决你的问题,请参考以下文章

SQL charindex怎么用

请问sql中CHARINDEX函数如何用,下面用法正确么?

如何写sql 语句,能删除字段中某个字符到最后字符串的?

如何写sql 语句,能删除字段中某个字符到最后字符串的?

Sql中CHARINDEX用法

Sql中CHARINDEX用法