是否有一种直接的方法可以使用SQL查找最后一次出现的字符串的索引?我现在正在使用SQL Server 2000。我基本上需要.NET System.String.LastIndexOf
方法提供的功能。一个小小的谷歌搜索显示了这个 - Function To Retrieve Last Index - 但如果你传入一个“文本”列表达式,这不起作用。在其他地方找到的其他解决方案只有在您搜索的文本长度为1个字符时才起作用。
我可能要做一个功能。如果我这样做,我会在这里发布,所以你们大家可以看看它,也许可以使用它。
答案 0 :(得分:161)
直截了当的方式?不,但我已经反过来了。字面上。
在先前的例程中,为了找到给定字符串的最后一次出现,我使用了REVERSE()函数,然后是CHARINDEX,再次使用REVERSE来恢复原始顺序。例如:
SELECT
mf.name
,mf.physical_name
,reverse(left(reverse(physical_name), charindex('\', reverse(physical_name)) -1))
from sys.master_files mf
显示了如何从“物理名称”中提取实际数据库文件名,无论嵌套在子文件夹中有多深。这只会搜索一个字符(反斜杠),但你可以在此基础上搜索更长的搜索字符串。
唯一的缺点是,我不知道这对TEXT数据类型有多好。我已经在SQL 2005上工作了几年,而且不再熟悉使用TEXT了 - 但我似乎记得你可以使用LEFT和RIGHT吗?
菲利普
答案 1 :(得分:95)
最简单的方法是......
REVERSE(SUBSTRING(REVERSE([field]),0,CHARINDEX('[expr]',REVERSE([field]))))
答案 2 :(得分:48)
如果您使用的是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
答案 3 :(得分:28)
您的文字数据类型仅限small list of functions。
我所能建议的只是从PATINDEX
开始,但是从DATALENGTH-1, DATALENGTH-2, DATALENGTH-3
等向后工作直到你得到一个结果或最终为零(DATALENGTH-DATALENGTH)
这确实是SQL Server 2000
根本无法处理的事情。
编辑其他答案:REVERSE不在SQL Server 2000中可与文本数据一起使用的函数列表中
答案 4 :(得分:14)
DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'
SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt
答案 5 :(得分:7)
这对我很有用。
REVERSE(SUBSTRING(REVERSE([field]), CHARINDEX(REVERSE('[expr]'), REVERSE([field])) + DATALENGTH('[expr]'), DATALENGTH([field])))
答案 6 :(得分:6)
旧的但仍然有效的问题,所以我根据其他人提供的信息创建了我所创建的内容。
create function fnLastIndexOf(@text varChar(max),@char varchar(1))
returns int
as
begin
return len(@text) - charindex(@char, reverse(@text)) -1
end
答案 7 :(得分:6)
REVERSE(SUBSTRING(REVERSE(ap_description),CHARINDEX('.',REVERSE(ap_description)),len(ap_description)))
对我来说效果更好
答案 8 :(得分:4)
嗯,我知道这是一个旧线程,但是一个计数表可以在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
获取每个分隔符的位置,然后您只需获得该集合中的最大位置。
Tally表非常棒。如果您之前没有使用它们,那么SQL Server Central上有一篇很好的文章(免费注册,或者只使用Bug Me Not(http://www.bugmenot.com/view/sqlservercentral.com))。
*编辑:已移除n <= LEN(TEXT_FIELD)
,因为您无法在TEXT类型上使用LEN()。只要substring(...) = @delim
仍然存在,但结果仍然正确。
答案 9 :(得分:2)
反转你的字符串和你的子字符串,然后搜索第一次出现。
答案 10 :(得分:2)
我意识到这是一个有几年历史的问题,但是......
在Access 2010
上,您可以使用InStrRev()
执行此操作。希望这会有所帮助。
答案 11 :(得分:1)
@indexOf = <whatever characters you are searching for in your string>
@LastIndexOf = LEN([MyField]) - CHARINDEX(@indexOf, REVERSE([MyField]))
没有经过测试,由于索引为零,它可能会被一个关闭,但是当从SUBSTRING
字符切换到字符串末尾时,它可以在@indexOf
函数中起作用
SUBSTRING([MyField], 0, @LastIndexOf)
答案 12 :(得分:1)
此答案使用MS SQL Server 2008(我没有访问MS SQL Server 2000的权限),但是根据OP的观察方式,有3种情况需要考虑。根据我没有尝试的答案,这里涵盖了所有这三个方面:
0
我想出的函数需要两个参数:
@String NVARCHAR(MAX)
:要搜索的字符串
@FindString NVARCHAR(MAX)
:使用单个字符或子字符串来获取最后一个
@String
它返回一个INT
,它是@FindString
中@String
或0
的正索引,表示@FindString
不在@String
中
以下是该功能的解释:
@ReturnVal
初始化为0
,表明@FindString
不在@String
中@FindString
检查@String
中CHARINDEX()
的索引@FindString
中@String
的索引是0
,则@ReturnVal
保留为0
@FindString
中@String
的索引是> 0
,则@FindString
在@String
中,因此
它使用@FindString
@String
中REVERSE()
的最后一个索引
@ReturnVal
,它是一个正数,它是的最后一个索引
@FindString
或@String
中的0
表示@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+起了作用。
享受。
答案 13 :(得分:1)
其他一些答案会返回一个实际的字符串,而我更需要知道实际的索引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(&#39;的最后一个索引:&#39;)
希望这对某人来说更容易一点!
答案 14 :(得分:1)
我知道效率低下但是您考虑将text
字段转换为varchar
,以便您可以使用您找到的网站提供的解决方案吗?我知道这个解决方案会产生问题,因为如果text
字段中的长度溢出varchar
的长度,你可能会截断记录(更不用说它不会非常高效)。
由于您的数据位于text
字段内(并且您使用的是SQL Server 2000),因此您的选项有限。
答案 15 :(得分:0)
要在分隔符最后一次出现之前获取该部分(由于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)));
答案 16 :(得分:0)
我需要在文件夹路径中找到反斜杠的第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
答案 17 :(得分:0)
这个答案符合OP的要求。特别是它允许针不仅仅是一个字符,并且在大海捞针中找不到针时不会产生错误。在我看来,大多数(所有?)其他答案都没有处理这些边缘情况。除此之外,我添加了&#34;起始位置&#34;由本机MS SQL服务器CharIndex函数提供的参数。我尝试完全镜像CharIndex的规范,除了从右到左而不是从左到右处理。例如,如果needle或haystack为null,则返回null,如果在haystack中找不到needle,则返回零。我无法解决的一件事是,使用内置函数,第三个参数是可选的。对于SQL Server用户定义的函数,除非使用&#34; EXEC&#34;来调用函数,否则必须在调用中提供所有参数。 。虽然第三个参数必须包含在参数列表中,但您可以提供关键字&#34;默认&#34;作为它的占位符而不必给它一个值(见下面的例子)。因为如果不需要,可以更容易地从该函数中删除第三个参数,如果需要的话,可以添加它作为起点。
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
答案 18 :(得分:0)
我在搜索我的类似问题的解决方案时遇到了这个问题,该解决方案具有完全相同的要求但是对于另一种也缺少REVERSE
函数的数据库。
在我的情况下,这是针对 OpenEdge(Progress)数据库,其语法略有不同。这使得INSTR
函数SELECT
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', ''))) AS IndexOfLastSlash
FROM foo
可以使用most Oracle typed databases offer。
所以我想出了以下代码:
SELECT
INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/', 'XX')) - LENGTH(foo.filepath)) AS IndexOfLastSlash
FROM foo
但是,对于我的特定情况(作为 OpenEdge(进度)数据库),这不会导致所需的行为,因为用空字符替换字符会给出与原始字符串相同的长度。这对我来说没有多大意义,但我能够通过以下代码绕过问题:
INSTR
现在我明白这段代码无法解决 T-SQL 的问题,因为除了提供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
函数可用时,您不需要创建此标量函数,您只需得到所需的结果:
{{1}}
答案 19 :(得分:0)
即使子字符串包含多个字符,此代码也有效。
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
答案 20 :(得分:0)
如果要获取字符串中最后一个空格的索引,可以使用此表达式 RIGHT(name,(CHARINDEX('',REVERSE(name),0))返回字符串中的最后一个单词。如果要解析包含第一个和第一个名称的首字母的全名的姓氏,这将非常有用。 /或中间名。
答案 21 :(得分:0)
处理lookinng大于1个字符的内容。 如果愿意,可以随意增加参数大小。
无法抗拒发布
drop function if exists lastIndexOf
go
create function lastIndexOf(@searchFor varchar(100),@searchIn varchar(500))
returns int
as
begin
if LEN(@searchfor) > LEN(@searchin) return 0
declare @r varchar(500), @rsp varchar(100)
select @r = REVERSE(@searchin)
select @rsp = REVERSE(@searchfor)
return len(@searchin) - charindex(@rsp, @r) - len(@searchfor)+1
end
和测试
select dbo.lastIndexof('greg','greg greg asdflk; greg sadf' ) -- 18
select dbo.lastIndexof('greg','greg greg asdflk; grewg sadf' ) --5
select dbo.lastIndexof(' ','greg greg asdflk; grewg sadf' ) --24