有没有一种简单的方法可以使用SQL查找字符串最后一次出现的索引?我现在正在使用SQL Server 2000。我基本上需要.NET System.String.LastIndexOf
方法提供的功能。稍作谷歌搜索就发现了这个功能 - 检索上一个索引的功能 -但是如果您传递“文本”列表达式则无法使用。只要您要搜索的文本长度为1个字符,其他地方找到的其他解决方案就可以使用。
我可能必须准备一个功能。如果这样做,我会将其发布在这里,以便大家查看并使用。
有没有一种简单的方法可以使用SQL查找字符串最后一次出现的索引?我现在正在使用SQL Server 2000。我基本上需要.NET System.String.LastIndexOf
方法提供的功能。稍作谷歌搜索就发现了这个功能 - 检索上一个索引的功能 -但是如果您传递“文本”列表达式则无法使用。只要您要搜索的文本长度为1个字符,其他地方找到的其他解决方案就可以使用。
我可能必须准备一个功能。如果这样做,我会将其发布在这里,以便大家查看并使用。
Answers:
我所建议的只是从开始PATINDEX
,但从DATALENGTH-1, DATALENGTH-2, DATALENGTH-3
etc 开始反向进行,直到获得结果或结束为零(DATALENGTH-DATALENGTH)
这确实是SQL Server 2000
无法处理的。
编辑其他答案:REVERSE不在SQL Server 2000中可与文本数据一起使用的功能列表中
DATALENGTH
返回字节数而不是字符。因此,DATALENGTH
对于NVARCHAR
字符串,返回2 x字符串中的字符数。 LEN
但是,返回的字符数减去任何结尾的空格。我从来没有使用DATALENGTH
字符长度计算,除非结尾的空白是显著,我肯定知道我的数据类型是一致的,不管他们是VARCHAR
或NVARCHAR
直截了当的方式?不,但是我已经使用了相反的方法。从字面上看。
在先前的例程中,为了查找给定字符串的最后一次出现,我使用了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吗?
菲利普
最简单的方法是...
REVERSE(SUBSTRING(REVERSE([field]),0,CHARINDEX('[expr]',REVERSE([field]))))
[expr]
符号超过1个,则也需要将其反转!
如果您使用的是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
嗯,我知道这是一个旧线程,但是统计表可以在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 Central上找到一篇不错的文章(免费注册,或者直接使用Bug Me Not(http://www.bugmenot.com/view/sqlservercentral.com))。
*编辑:已删除n <= LEN(TEXT_FIELD)
,因为您不能在TEXT类型上使用LEN()。只要substring(...) = @delim
仍然存在,结果仍然是正确的。
其他一些答案返回实际的字符串,而我更需要知道实际的索引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(“:”的最后一个索引)
希望这会使某人更轻松!
该答案使用MS SQL Server 2008(我没有访问MS SQL Server 2000的权限),但是根据OP的观察方式,有3种情况需要考虑。根据我没有尝试的答案,这里涵盖了所有这三个方面:
0
我想出的函数需要两个参数:
@String NVARCHAR(MAX)
:要搜索的字符串
@FindString NVARCHAR(MAX)
:使用单个字符或子字符串获取in的最后一个索引 @String
它返回一个in INT
的正索引或表示@FindString
@String
0
@FindString
。@String
这是对该功能的解释:
@ReturnVal
以0
指示@FindString
不在@String
@FindString
中@String
使用CHARINDEX()
@FindString
in 的索引@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+起了作用。
请享用。
如果要获取单词字符串中最后一个空格的索引,可以使用此表达式RIGHT(name,(CHARINDEX('',REVERSE(name),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
我需要在文件夹路径中找到反斜线的第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
该答案符合OP的要求。特别是它允许针不止一个字符,并且在干草堆中找不到针时也不会产生错误。在我看来,大多数(全部?)其他答案都没有处理那些极端情况。除此之外,我还添加了本机MS SQL Server CharIndex函数提供的“起始位置”参数。我尝试完全反映CharIndex的规范,除了从右到左而不是从左到右处理。例如,如果needle或haystack中的任何一个为null,我将返回null;如果在haystack中未找到needle,我将返回零。我无法解决的一件事是,使用内置函数,第三个参数是可选的。对于SQL Server用户定义的函数,除非使用“ EXEC”调用该函数,否则必须在调用中提供所有参数。。尽管第三个参数必须包含在参数列表中,但是您可以为其提供关键字“ default”作为占位符,而不必为其提供值(请参见下面的示例)。因为如果不需要,从此函数中删除第三个参数比在需要时添加第三个参数更容易,所以在此我将其包括在内。
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
我在寻找类似问题的解决方案时遇到了这个问题,该解决方案具有完全相同的要求,但针对的是另一种缺少数据库的数据库 REVERSE
功能。
在我的情况下,这是针对OpenEdge(Progress)数据库的,该数据库的语法略有不同。这使INSTR
我可以使用大多数Oracle类型数据库提供的功能。
所以我想出了以下代码:
SELECT
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', ''))) AS IndexOfLastSlash
FROM foo
但是,对于我的特定情况(作为OpenEdge(Progress)数据库),这并没有导致所需的行为,因为用空字符替换字符会得到与原始字符串相同的长度。这对我来说没有多大意义,但是我可以通过下面的代码绕过该问题:
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