如何在另一个字符串中找到一个字符串的所有位置

cod*_*ori 11 sql-server-2005 sql-server string-searching

如何patindex在表格或变量中找到所有位置?

declare @name nvarchar(max)
set @name ='ali reza dar yek shabe barani ba yek  '
  + 'dokhtare khoshkel be disco raft va ali baraye'
  + ' 1 saat anja bud va sepas... ali...'
select patindex('%ali%',@name) as pos 
Run Code Online (Sandbox Code Playgroud)

这会返回1但我想要所有结果,例如:

pos
===
  1
 74
113
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 15

我认为这将比您选择的循环方法(这里有一些证据)更有效,并且绝对比递归 CTE 更有效:

CREATE FUNCTION dbo.FindPatternLocation
(
    @string NVARCHAR(MAX),
    @term   NVARCHAR(255)
)
RETURNS TABLE
AS
    RETURN 
    (
      SELECT pos = Number - LEN(@term) 
      FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@string, Number, 
      CHARINDEX(@term, @string + @term, Number) - Number)))
      FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
      FROM sys.all_objects) AS n(Number)
      WHERE Number > 1 AND Number <= CONVERT(INT, LEN(@string)+1)
      AND SUBSTRING(@term + @string, Number, LEN(@term)) = @term
    ) AS y);
Run Code Online (Sandbox Code Playgroud)

示例用法:

DECLARE @name NVARCHAR(MAX);

SET @name = N'ali reza dar yek shabe barani ba yek'
    + '  dokhtare khoshkel be disco raft va ali baraye '
    + '1 saat anja bud va sepas... ali...';

SELECT pos FROM dbo.FindPatternLocation(@name, 'ali');
Run Code Online (Sandbox Code Playgroud)

结果:

pos
---
  1
 74
113
Run Code Online (Sandbox Code Playgroud)

如果您的字符串将超过 2K,则使用 sys.all_columns 而不是 sys.all_objects。如果长于 8K,则添加交叉连接。


bum*_*mmi 9

declare @name nvarchar(max)
set @name ='ali reza dar yek shabe barani ba yek  dokhtare khoshkel be disco raft va ali baraye 1 saat anja bud va sepas... ali...'

Declare @a table (pos int)
Declare @pos int
Declare @oldpos int
Select @oldpos=0
select @pos=patindex('%ali%',@name) 
while @pos > 0 and @oldpos<>@pos
 begin
   insert into @a Values (@pos)
   Select @oldpos=@pos
   select @pos=patindex('%ali%',Substring(@name,@pos + 1,len(@name))) + @pos
end

Select * from @a
Run Code Online (Sandbox Code Playgroud)

为了使其可重用,您可以在表函数中使用它来调用它:

Select * from  dbo.F_CountPats ('ali reza dar yek shabe barani ba yek  dokhtare khoshkel be disco raft va ali baraye 1 saat anja bud va sepas... ali...','%ali%')
Run Code Online (Sandbox Code Playgroud)

该功能可能如下所示

Create FUNCTION [dbo].[F_CountPats] 
(
@txt varchar(max),
@Pat varchar(max)
)
RETURNS 
@tab TABLE 
(
 ID int
)
AS
BEGIN
Declare @pos int
Declare @oldpos int
Select @oldpos=0
select @pos=patindex(@pat,@txt) 
while @pos > 0 and @oldpos<>@pos
 begin
   insert into @tab Values (@pos)
   Select @oldpos=@pos
   select @pos=patindex(@pat,Substring(@txt,@pos + 1,len(@txt))) + @pos
end

RETURN 
END

GO
Run Code Online (Sandbox Code Playgroud)

  • @Misiu 正如预期的那样,Aaron Bertrands 的解决方案不仅更优雅,而且比我的要快得多,应该是公认的解决方案。您可以使用更大的输入轻松测试,使用他的示例只需在调用 *SELECT pos FROM dbo.FindPatternLocation(@name, 'ali');* 之前添加 *SET @name=Replicate(@name,5000)* 并尝试与我的缓慢程序相同。 (2认同)