AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 41961
Accepted
Ario
Ario
Asked: 2013-05-11 15:12:31 +0800 CST2013-05-11 15:12:31 +0800 CST 2013-05-11 15:12:31 +0800 CST

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

  • 772

如何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 

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

pos
===
  1
 74
113
sql-server sql-server-2005
  • 7 7 个回答
  • 58483 Views

7 个回答

  • Voted
  1. Aaron Bertrand
    2013-05-13T05:14:26+08:002013-05-13T05:14:26+08:00

    我认为这将比您选择的循环方法更有效(这里有一些证据),并且肯定比递归 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);
    

    示例用法:

    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');
    

    结果:

    pos
    ---
      1
     74
    113
    

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

    • 17
  2. Best Answer
    bummi
    2013-05-12T00:38:52+08:002013-05-12T00:38:52+08:00
    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
    

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

    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%')
    

    该功能可能如下所示

    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
    
    • 9
  3. msi77
    2013-05-12T08:05:15+08:002013-05-12T08:05:15+08:00

    --递归CTE

    with cte as
    (select 'ali reza dar yek shabe barani ba yek  dokhtare khoshkel be disco raft va ali baraye 1 saat anja bud va sepas... ali...' as name
    ), 
    pos as
    (select patindex('%ali%',name) pos, name from cte
    union all
    select pos+patindex('%ali%',substring(name, pos+1, len(name))) pos, name from pos
    where patindex('%ali%',substring(name, pos+1, len(name)))>0
    )
    select pos from pos
    
    • 2
  4. Nils
    2015-07-29T00:08:53+08:002015-07-29T00:08:53+08:00

    我喜欢 Aaron Bertrand 的回答。虽然没完全看懂,但是看起来真的很优雅。

    过去我在使用sys.objects. 结合我对代码进行故障排除的需要,我提出了 Aaron 代码的变体,并在下面添加了它。

    这是我的程序:

    CREATE PROCEDURE dbo.FindPatternLocations
    -- Params
    @TextToSearch nvarchar (max),
    @TextToFind nvarchar (255)
    
    AS
    BEGIN
    
        declare @Length int
        set @Length = (Select LEN(@TextToSearch))
    
        declare @LengthSearchString int
        set @LengthSearchString = (select LEN (@TextToFind))
    
        declare @Index int
        set @Index=1
    
        create table #Positions (
        [POSID] [int] IDENTITY(0,1) NOT FOR REPLICATION NOT NULL,
        POS int
        )
    
        insert into #Positions (POS) select 0 -- to return a row even if no findings occur
    
            set @Index = (select charindex(@TextToFind, @TextToSearch, @Index))
                        if @Index = 0 goto Ende -- TextToFind is not in TextToSearch
    
            insert into #Positions (POS) select @Index
    
    
            set @Index = @Index + @LengthSearchString
    
    while @Index <= @Length - @LengthSearchString   
        Begin
                set @Index = (select charindex(@TextToFind, @TextToSearch, @Index) )
                if @Index = 0 goto Ende -- no findings anymore
                insert into #Positions (POS) select @Index
                set @Index = @Index + @LengthSearchString
        end
    Ende:
    if (select MAX(posid) from #Positions) > 0 delete from #Positions where POSID = 0 -- row is not needed if TextToFind occurs
    select * from #Positions
    END
    GO
    

    该MAX(posid)值也是找到的匹配数。

    • 0
  5. JotaPardo
    2017-01-05T07:36:04+08:002017-01-05T07:36:04+08:00

    这是一个基于Aaron 回答的简单代码:

    • 不限于 sys.all_objects 的大小
    • 不要错过最后一个'X'

    代码:

    DECLARE @termToFind CHAR(1) = 'X'
    DECLARE @string VARCHAR(40) = 'XX XXX  X   XX'
    
    SET @string += '.' --Add any data here (different from the one searched) to get the position of the last character
    
    DECLARE @stringLength BIGINT = len(@string)
    
    SELECT pos = Number - LEN(@termToFind)
    FROM (
        SELECT Number
            , Item = LTRIM(RTRIM(SUBSTRING(@string, Number, CHARINDEX(@termToFind, @string + @termToFind, Number) - Number)))
        FROM (
            --All numbers between 1 and the lengh of @string. Better than use sys.all_objects
            SELECT TOP (@stringLength) row_number() OVER (
                    ORDER BY t1.number
                    ) AS N
            FROM master..spt_values t1
            CROSS JOIN master..spt_values t2
            ) AS n(Number)
        WHERE Number > 1
            AND Number <= CONVERT(INT, LEN(@string))
            AND SUBSTRING(@termToFind + @string, Number, LEN(@termToFind)) = @termToFind
        ) AS y
    

    结果

    pos
    --------------------
    1
    2
    4
    5
    6
    9
    13
    14
    
    (8 row(s) affected)
    
    • 0
  6. OzrenTkalcecKrznaric
    2019-11-23T07:38:03+08:002019-11-23T07:38:03+08:00

    抱歉,这么晚了,但我想让那些想要扩展它的人更容易。我查看了这些实现中的每一个,选择了对我来说最好的一个(Aaron Bertrand),简化了它,然后你就得到了“模板”。明智地使用它。

    CREATE FUNCTION dbo.CHARINDICES (
        @search_expression NVARCHAR(4000),
        @expression_to_be_searched NVARCHAR(MAX)
    ) RETURNS TABLE AS RETURN (
        WITH tally AS (
            SELECT Number = ROW_NUMBER() OVER (ORDER BY [object_id])
            FROM sys.all_objects)
        SELECT DISTINCT n = subIdx -- (4) if we don't perform distinct we'll get result for each searched substring, and we don't want that
        FROM 
            tally 
            CROSS APPLY (SELECT subIdx = CHARINDEX(@search_expression, @expression_to_be_searched, Number)) x -- (2) subIdx is found in the rest of the substring 
        WHERE 
            Number BETWEEN 1 AND LEN(@expression_to_be_searched) -- (1) run for each substring once
            AND SubIdx != 0  -- (3) we care only about the indexes we've found, 0 stands for "not found"
    )
    
    SELECT CHARINDEX('C', 'BACBABCBABBCBACBBABC')
    SELECT * FROM dbo.CHARINDICES('C', 'BACBABCBABBCBACBBABC')
    

    作为参考 - 您可以从中派生其他行为,例如扩展 PATINDEX():

    CREATE FUNCTION dbo.PATINDICES (
        @search_expression NVARCHAR(4000) = '%[cS]%',
        @expression_to_be_searched NVARCHAR(MAX) = 'W3Schools.com'
    ) RETURNS TABLE AS RETURN (
        WITH tally AS (
            SELECT num = ROW_NUMBER() OVER (ORDER BY [object_id])
            FROM sys.all_objects)
        SELECT DISTINCT n = subIdx + num - 1
        FROM 
            tally 
            CROSS APPLY (SELECT numRev = LEN(@expression_to_be_searched) - num + 1) x
            CROSS APPLY (SELECT subExp = RIGHT(@expression_to_be_searched, numRev)) y
            CROSS APPLY (SELECT subIdx = PATINDEX(@search_expression, subExp)) z
        WHERE 
            num BETWEEN 1 AND LEN(@expression_to_be_searched)
            AND SubIdx != 0
    )
    
    SELECT PATINDEX('%[cS]%', 'W3Schools.com')
    SELECT * FROM dbo.PATINDICES('%[cS]%', 'W3Schools.com')
    
    • 0
  7. Raghu
    2019-12-17T21:09:31+08:002019-12-17T21:09:31+08:00
    Declare @search varchar(5)
        sET @search='a'
        Declare @name varchar(40)
        Set @name='AmitabhBachan'
        Declare @init int
        Set @init=1
        Declare @hold int
        Declare @table table (POSITION Int)
        While( @init<= LEn(@name))
        Begin
       Set @hold=(Select CHARINDEX(@search,@name,@init))
       If (@hold!=0)
       BEgin 
       --Print @hold
       Insert into @table
       Select @hold
       Set @init=@hold+1
       End 
       Else
       If (@hold=0)
       BEgin
       Break
       End
      End
      Select * from @table
    
    • 0

相关问题

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve