使用T-SQL查找子字符串中最后一次出现的索引使用T-SQL查找子字符串中最后一次出现的索引(Fin

2019-05-13 14:50发布

有没有找到使用SQL字符串中最后一次出现的索引的一种简单的方法? 我使用SQL Server 2000的现在。 基本上,我需要的是.NET的功能System.String.LastIndexOf方法提供。 一个小Googling透露这一点- 函数来获取最后一个索引 -但如果你在“文本”列表达式传递不起作用。 在其他地方找到其他的解决方案只工作,只要您正在搜索的文本为1个字符长。

我可能会做饭的功能了。 如果我这样做,我将它张贴在这里,所以你的乡亲可以看看它,也许利用。

Answer 1:

你是有限的功能小列表的文本数据类型。

所有我可以建议是开始PATINDEX ,但向后工作DATALENGTH-1, DATALENGTH-2, DATALENGTH-3等,直到你得到的结果,或者在零结束(DATALENGTH,DATALENGTH)

这确实是一件SQL Server 2000根本无法处理。

编辑其他答案 :REVERSE是不是可以用文本数据在SQL Server 2000中使用的功能列表中



Answer 2:

简单的方法是什么? 没有,但我已经使用了反向。 从字面上看。

在以前的套路,找到一个给定的字符串的最后一个实例,我用REVERSE()函数,然后CHARINDEX,随后再次反向恢复原来的秩序。 例如:

SELECT
   mf.name
  ,mf.physical_name
  ,reverse(left(reverse(physical_name), charindex('\', reverse(physical_name)) -1))
 from sys.master_files mf

显示了如何从他们的“物理名称”提取实际的数据库文件名,不管有多深嵌套子文件夹中。 但这仅搜索一个字符(反斜线),但你可以建立在这个较长的搜索字符串。

唯一不足的是,我不知道该怎么好,这将文本数据类型的工作。 我一直在几年SQL 2005,现在,我没有用TEXT工作更精通 - 但我似乎记得,你可以使用左右就可以了?

菲利普



Answer 3:

最简单的方法是....

REVERSE(SUBSTRING(REVERSE([field]),0,CHARINDEX('[expr]',REVERSE([field]))))


Answer 4:

如果使用的是sqlserver的2005或以上,使用REVERSE功能很多次会降低性能,下面的代码是更有效的。

DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'

-- Shows text before last slash
SELECT LEFT(@FilePath, LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath))) AS Before
-- Shows text after last slash
SELECT RIGHT(@FilePath, CHARINDEX(@FindChar,REVERSE(@FilePath))-1) AS After
-- Shows the position of the last slash
SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt


Answer 5:

DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'

SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt


Answer 6:

这个工作对我非常好。

REVERSE(SUBSTRING(REVERSE([field]), CHARINDEX(REVERSE('[expr]'), REVERSE([field])) + DATALENGTH('[expr]'), DATALENGTH([field])))


Answer 7:

老了,但仍然有效的问题的基础上,由他人这里提供的信息,以便继承人是我创建的。

create function fnLastIndexOf(@text varChar(max),@char varchar(1))
returns int
as
begin
return len(@text) - charindex(@char, reverse(@text)) -1
end


Answer 8:

REVERSE(SUBSTRING(REVERSE(ap_description),CHARINDEX('.',REVERSE(ap_description)),len(ap_description)))  

工作更好地为我



Answer 9:

嗯,我知道这是一个古老的线程,但符合表可以在SQL2000(或任何其他数据库)这样做:

DECLARE @str CHAR(21),
        @delim CHAR(1)
 SELECT @str = 'Your-delimited-string',
        @delim = '-'

SELECT
    MAX(n) As 'position'
FROM
    dbo._Tally
WHERE
    substring(@str, _Tally.n, 1) = @delim

理货表只是一个递增的数字的表格。

substring(@str, _Tally.n, 1) = @delim获取每个分隔符的位置,那么你只能在该组的最大位置。

理货表是真棒。 如果你以前没有使用过他们,有一个很好的文章SQL Server管理中心 (免费REG,或者只是使用虫不知( http://www.bugmenot.com/view/sqlservercentral.com ))。

*编辑:删除n <= LEN(TEXT_FIELD)因为你不能在TEXT类型使用LEN()。 只要substring(...) = @delim仍尽管结果仍然是正确的。



Answer 10:

反向既您的字符串和你的子,然后搜索第一次出现。



Answer 11:

我意识到这是一个好几年的老问题,但...

Access 2010 ,您可以使用InStrRev()来做到这一点。 希望这可以帮助。



Answer 12:

我知道,这将是低效的,但是你有没有考虑铸造text字段varchar ,这样你可以使用该网站提供的解决方案,你发现了什么? 我知道,这个解决方案会产生问题,你可能会截断记录,如果在长度text字段溢出您的长度varchar (更不用说它不会是非常高性能的)。

由于您的数据是内部text字段(和你正在使用SQL Server 2000),您的选择是有限的。



Answer 13:

@indexOf = <whatever characters you are searching for in your string>

@LastIndexOf = LEN([MyField]) - CHARINDEX(@indexOf, REVERSE([MyField]))

没有测试,它可能是由一个因为零指数处于关闭状态,但在工作SUBSTRING从斩去时功能@indexOf字符来结束你的字符串

SUBSTRING([MyField], 0, @LastIndexOf)



Answer 14:

一些其他的答案返回一个实际的字符串,而我更需要知道实际的指数INT。 而且这样做似乎是答案的事情过分复杂化。 使用一些其他的答案为灵感的,我做了以下...

首先,我创建了一个功能:

CREATE FUNCTION [dbo].[LastIndexOf] (@stringToFind varchar(max), @stringToSearch varchar(max))
RETURNS INT
AS
BEGIN
    RETURN (LEN(@stringToSearch) - CHARINDEX(@stringToFind,REVERSE(@stringToSearch))) + 1
END
GO

然后,在你的查询,你可以简单地这样做:

declare @stringToSearch varchar(max) = 'SomeText: SomeMoreText: SomeLastText'

select dbo.LastIndexOf(':', @stringToSearch)

上述应返回23(最后指数“:”)

希望这使得它的人更容易一些!



Answer 15:

这个答案使用MS SQL Server 2008中(我没有访问MS SQL Server 2000中),但我根据OP看到它的方式是3种情况来考虑。 从我已经试过没有答案在这里涵盖了所有的人都3:

  1. 返回给定的字符串中搜索字符的最后索引。
  2. 一个给定的字符串中返回一个搜索子串(不仅仅是单个字符以上)的最后一个索引。
  3. 如果搜索字符或子串是不是在给定的字符串返回0

我想出了这个功能需要两个参数:

@String NVARCHAR(MAX)在被搜索的字符串

@FindString NVARCHAR(MAX)无论是单个字符或子串来获得在最后一个索引@String

它返回一个INT是任阳性指数@FindString@String0含义@FindString不在@String

这里的功能所做的解释:

  1. 初始化@ReturnVal0指示@FindString不在@String
  2. 检查的索引@FindString@String通过使用CHARINDEX()
  3. 如果指数@FindString@String0@ReturnVal保留为0
  4. 如果指数@FindString@String> 0@FindString是在@String所以它计算的最后一个索引@FindString@String通过使用REVERSE()
  5. 返回@ReturnVal其或者正数即最后索引@FindString@String0指示@FindString不在@String

下面是创建功能脚本(复制和粘贴准备):

CREATE FUNCTION [dbo].[fn_LastIndexOf] 
(@String NVARCHAR(MAX)
, @FindString NVARCHAR(MAX))
RETURNS INT
AS 
BEGIN
    DECLARE @ReturnVal INT = 0
    IF CHARINDEX(@FindString,@String) > 0
        SET @ReturnVal = (SELECT LEN(@String) - 
        (CHARINDEX(REVERSE(@FindString),REVERSE(@String)) + 
        LEN(@FindString)) + 2)  
    RETURN @ReturnVal
END

下面是方便测试功能,一点点:

DECLARE @TestString NVARCHAR(MAX) = 'My_sub2_Super_sub_Long_sub1_String_sub_With_sub_Long_sub_Words_sub2_'
, @TestFindString NVARCHAR(MAX) = 'sub'

SELECT dbo.fn_LastIndexOf(@TestString,@TestFindString)

我只MS SQL Server 2008上运行,是因为我没有获得任何其他版本,但是从我看着这应该2008+至少是好的。

请享用。



Answer 16:

如果你想获得最后空间的指数一串字,你可以用这个表达RIGHT(名称,(CHARINDEX(””,反向(名称),0))返回字符串中的最后一个字。这如果你想解析出包括第一和/或中间名缩写全名的姓氏是有帮助的。



Answer 17:

我需要找到一个文件夹路径反斜杠的第n个最后的位置。 这里是我的解决方案。

/*
http://stackoverflow.com/questions/1024978/find-index-of-last-occurrence-of-a-sub-string-using-t-sql/30904809#30904809
DROP FUNCTION dbo.GetLastIndexOf
*/
CREATE FUNCTION dbo.GetLastIndexOf
(
  @expressionToFind         VARCHAR(MAX)
  ,@expressionToSearch      VARCHAR(8000)
  ,@Occurrence              INT =  1        -- Find the nth last 
)
RETURNS INT
AS
BEGIN

    SELECT  @expressionToSearch = REVERSE(@expressionToSearch)

    DECLARE @LastIndexOf        INT = 0
            ,@IndexOfPartial    INT = -1
            ,@OriginalLength    INT = LEN(@expressionToSearch)
            ,@Iteration         INT = 0

    WHILE (1 = 1)   -- Poor man's do-while
    BEGIN
        SELECT @IndexOfPartial  = CHARINDEX(@expressionToFind, @expressionToSearch)

        IF (@IndexOfPartial = 0) 
        BEGIN
            IF (@Iteration = 0) -- Need to compensate for dropping out early
            BEGIN
                SELECT @LastIndexOf = @OriginalLength  + 1
            END
            BREAK;
        END

        IF (@Occurrence > 0)
        BEGIN
            SELECT @expressionToSearch = SUBSTRING(@expressionToSearch, @IndexOfPartial + 1, LEN(@expressionToSearch) - @IndexOfPartial - 1)
        END

        SELECT  @LastIndexOf = @LastIndexOf + @IndexOfPartial
                ,@Occurrence = @Occurrence - 1
                ,@Iteration = @Iteration + 1

        IF (@Occurrence = 0) BREAK;
    END

    SELECT @LastIndexOf = @OriginalLength - @LastIndexOf + 1 -- Invert due to reverse
    RETURN @LastIndexOf 
END
GO

GRANT EXECUTE ON GetLastIndexOf TO public
GO

这里是我的测试案例,其通过

SELECT dbo.GetLastIndexOf('f','123456789\123456789\', 1) as indexOf -- expect 0 (no instances)
SELECT dbo.GetLastIndexOf('\','123456789\123456789\', 1) as indexOf -- expect 20
SELECT dbo.GetLastIndexOf('\','123456789\123456789\', 2) as indexOf -- expect 10
SELECT dbo.GetLastIndexOf('\','1234\6789\123456789\', 3) as indexOf -- expect 5


Answer 18:

为了分隔符的最后一次出现之前获得的部分(仅适用于NVARCHAR由于DATALENGTH用法):

DECLARE @Fullstring NVARCHAR(30) = '12.345.67890.ABC';

DECLARE @Delimiter CHAR(1) = '.';

SELECT SUBSTRING(@Fullstring, 1, DATALENGTH(@Fullstring)/2 - CHARINDEX(@Delimiter, REVERSE(@Fullstring)));


Answer 19:

这个答案符合OP的要求。 具体地,其允许针为比单个字符更并且当在草堆未找到针它不产生一个错误。 在我看来,其他的答案大多数(全部?)没有处理的边缘情况。 除此之外,我还通过本地MS SQL服务器CHARINDEX函数提供“起始位置”的说法。 我试图为CHARINDEX规范准确反映除了到左,而不是从左到右程序的权利。 例如,我返回null如果任一针或草垛为空,我回零,如果针头未在草堆里找到。 有一两件事,我无法避开的是,与内置的函数的第三个参数是可选。 在SQL Server用户自定义函数,所有参数必须在通话中提供,除非该功能是使用“EXEC”之称。 而第三个参数必须包含在参数列表中,您可以提供关键字“默认”作为它的占位符,而不必给它一个值(见下面的例子)。 因为它是比较容易,如果不希望这个函数删除第三个参数比起来,如果需要,我在这里为起点,包括它来添加。

create function dbo.lastCharIndex(
 @needle as varchar(max),
 @haystack as varchar(max),
 @offset as bigint=1
) returns bigint as begin
 declare @position as bigint
 if @needle is null or @haystack is null return null
 set @position=charindex(reverse(@needle),reverse(@haystack),@offset)
 if @position=0 return 0
 return (len(@haystack)-(@position+len(@needle)-1))+1
end
go

select dbo.lastCharIndex('xyz','SQL SERVER 2000 USES ANSI SQL',default) -- returns 0
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',default) -- returns 27
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',1) -- returns 27
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',11) -- returns 1


Answer 20:

我碰到这个线程来同时寻找解决我类似的问题,其中有完全相同的要求,但对于不同类型的数据库,这也是缺乏REVERSE功能。

在我的情况,这是一个OpenEdge(进度)数据库,该数据库有一个稍微不同的语法。 这使得INSTR提供的功能,我认为大多数Oracle数据库的输入提供 。

所以,我想出了下面的代码:

SELECT 
  INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/',  ''))) AS IndexOfLastSlash 
FROM foo

但是,对于我的具体情况(为OpenEdge(进度)数据库),这并不会导致到所需的行为,因为用空字符替换字符给了相同长度的原始字符串。 这并没有太大的意义给我,但我能够绕过与下面的代码的问题:

SELECT 
  INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/',  'XX')) - LENGTH(foo.filepath))  AS IndexOfLastSlash 
FROM foo

现在我明白了,因为没有替代这个代码将不会解决T-SQL的问题INSTR ,提供的功能Occurence财产。

只是要彻底的,我会加入到创建此标量函数,因此可以使用相同的方式就像我在上面的例子中确实需要的代码。

  -- Drop the function if it already exists
  IF OBJECT_ID('INSTR', 'FN') IS NOT NULL
    DROP FUNCTION INSTR
  GO

  -- User-defined function to implement Oracle INSTR in SQL Server
  CREATE FUNCTION INSTR (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
  RETURNS INT
  AS
  BEGIN
    DECLARE @found INT = @occurrence,
            @pos INT = @start;

    WHILE 1=1 
    BEGIN
        -- Find the next occurrence
        SET @pos = CHARINDEX(@substr, @str, @pos);

        -- Nothing found
        IF @pos IS NULL OR @pos = 0
            RETURN @pos;

        -- The required occurrence found
        IF @found = 1
            BREAK;

        -- Prepare to find another one occurrence
        SET @found = @found - 1;
        SET @pos = @pos + 1;
    END

    RETURN @pos;
  END
  GO

为了避免明显的,当REVERSE功能可用,你不需要创建这个标量函数和你可以得到这样的要求的结果:

SELECT
  LEN(foo.filepath) - CHARINDEX('/', REVERSE(foo.filepath))+1 AS LastIndexOfSlash 
FROM foo


Answer 21:

此代码的工作,即使子包含超过1个字符。

DECLARE @FilePath VARCHAR(100) = 'My_sub_Super_sub_Long_sub_String_sub_With_sub_Long_sub_Words'
DECLARE @FindSubstring VARCHAR(5) = '_sub_'

-- Shows text before last substing
SELECT LEFT(@FilePath, LEN(@FilePath) - CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) - LEN(@FindSubstring) + 1) AS Before
-- Shows text after last substing
SELECT RIGHT(@FilePath, CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) -1) AS After
-- Shows the position of the last substing
SELECT LEN(@FilePath) - CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) AS LastOccuredAt


文章来源: Find index of last occurrence of a sub-string using T-SQL