SQL 服务器中是否有 LastIndexOf?
Is there a LastIndexOf in SQL Server?
我正在尝试从涉及获取 last index of a string 的字符串中解析出一个值。目前,我正在做一个涉及反转字符串的可怕黑客:
SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1,
CHARINDEX('_', REVERSE(DB_NAME()), 1) - 1))
对我来说这段代码几乎不可读。我刚刚升级到 SQL Server 2016,我希望有更好的方法。
有吗?
如果您想要最后一个 _
之后的所有内容,请使用:
select right(db_name(), charindex('_', reverse(db_name()) + '_') - 1)
如果你想要以前的一切,那么使用left()
:
select left(db_name(), len(db_name()) - charindex('_', reverse(db_name()) + '_'))
一旦你拥有 split strings from here 之一,你就可以像这样以基于集合的方式来完成它..
declare @string varchar(max)
set @string='C:\Program Files\Microsoft SQL Server\MSSQL\DATA\AdventureWorks_Data.mdf'
;with cte
as
(select *,row_number() over (order by (select null)) as rownum
from [dbo].[SplitStrings_Numbers](@string,'\')
)
select top 1 item from cte order by rownum desc
**Output:**
AdventureWorks_Data.mdf
不,SQL 服务器没有 LastIndexOf。
这是可用的字符串 functions
但您始终可以创建自己的函数
CREATE FUNCTION dbo.LastIndexOf(@source text, @pattern char)
RETURNS
AS
BEGIN
DECLARE @ret text;
SELECT into @ret
REVERSE(SUBSTRING(REVERSE(@source), 1,
CHARINDEX(@pattern, REVERSE(@source), 1) - 1))
RETURN @ret;
END;
GO
我在寻找解决我的类似问题的解决方案时遇到了这个线程,该问题具有完全相同的要求,但适用于缺少 REVERSE
函数的不同类型的数据库。
在我的例子中,这是针对 OpenEdge (Progress) 数据库的,它的语法略有不同。这使我可以使用 INSTR
函数 most Oracle typed databases offer.
所以我想出了下面的代码:
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
属性.
为了完整起见,我将添加创建此标量函数所需的代码,以便可以像我在上述示例中那样使用它。并将完全按照 OP 的要求进行操作,作为 SQL 服务器的 LastIndexOf 方法。
-- 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
为所选字符编写了 2 个函数,1 到 return LastIndexOf。
CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(80), @pattern char)
RETURNS int
BEGIN
RETURN (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
END;
GO
and 1 to return 这个 LastIndexOf 之前的一个字符串。也许对某人有用。
CREATE FUNCTION dbo.StringBeforeLastIndex(@source nvarchar(80), @pattern char)
RETURNS nvarchar(80)
BEGIN
DECLARE @lastIndex int
SET @lastIndex = (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
RETURN SUBSTRING(@source, 0, @lastindex + 1)
-- +1 because index starts at 0, but length at 1, so to get up to 11th index, we need LENGTH 11+1=12
END;
GO
CREATE FUNCTION dbo.LastIndexOf(@text NTEXT, @delimiter NTEXT)
RETURNS INT
AS
BEGIN
IF (@text IS NULL) RETURN NULL;
IF (@delimiter IS NULL) RETURN NULL;
DECLARE @Text2 AS NVARCHAR(MAX) = @text;
DECLARE @Delimiter2 AS NVARCHAR(MAX) = @delimiter;
DECLARE @Index AS INT = CHARINDEX(REVERSE(@Delimiter2), REVERSE(@Text2));
IF (@Index < 1) RETURN 0;
DECLARE @ContentLength AS INT = (LEN('|' + @Text2 + '|') - 2);
DECLARE @DelimiterLength AS INT = (LEN('|' + @Delimiter2 + '|') - 2);
DECLARE @Result AS INT = (@ContentLength - @Index - @DelimiterLength + 2);
RETURN @Result;
END
- 允许使用多字符分隔符,例如“,”(逗号 space)。
- Returns 如果未找到分隔符,则返回 0。
- 出于舒适原因采用 NTEXT,因为 NVARCHAR(MAX) 隐含地转换为 NTEXT,但反之则不然。
- 正确处理带前导或尾部的分隔符 space!
试试这个。
drop table #temp
declare @brokername1 nvarchar(max)='indiabullssecurities,canmoney,indianivesh,acumencapitalmarket,sharekhan,edelweisscapital';
Create Table #temp
(
ID int identity(1,1) not null,
value varchar(100) not null
)
INSERT INTO #temp(value) SELECT value from STRING_SPLIT(@brokername1,',')
declare @id int;
set @id=(select max(id) from #temp)
--print @id
declare @results varchar(500)
select @results = coalesce(@results + ',', '') + convert(varchar(12),value)
from #temp where id<@id
order by id
print @results
尝试:
select LEN('tran van abc') + 1 - CHARINDEX(' ', REVERSE('tran van abc'))
因此,“ ”的最后一个索引是:9
我正在尝试从涉及获取 last index of a string 的字符串中解析出一个值。目前,我正在做一个涉及反转字符串的可怕黑客:
SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1,
CHARINDEX('_', REVERSE(DB_NAME()), 1) - 1))
对我来说这段代码几乎不可读。我刚刚升级到 SQL Server 2016,我希望有更好的方法。 有吗?
如果您想要最后一个 _
之后的所有内容,请使用:
select right(db_name(), charindex('_', reverse(db_name()) + '_') - 1)
如果你想要以前的一切,那么使用left()
:
select left(db_name(), len(db_name()) - charindex('_', reverse(db_name()) + '_'))
一旦你拥有 split strings from here 之一,你就可以像这样以基于集合的方式来完成它..
declare @string varchar(max)
set @string='C:\Program Files\Microsoft SQL Server\MSSQL\DATA\AdventureWorks_Data.mdf'
;with cte
as
(select *,row_number() over (order by (select null)) as rownum
from [dbo].[SplitStrings_Numbers](@string,'\')
)
select top 1 item from cte order by rownum desc
**Output:**
AdventureWorks_Data.mdf
不,SQL 服务器没有 LastIndexOf。
这是可用的字符串 functions
但您始终可以创建自己的函数
CREATE FUNCTION dbo.LastIndexOf(@source text, @pattern char)
RETURNS
AS
BEGIN
DECLARE @ret text;
SELECT into @ret
REVERSE(SUBSTRING(REVERSE(@source), 1,
CHARINDEX(@pattern, REVERSE(@source), 1) - 1))
RETURN @ret;
END;
GO
我在寻找解决我的类似问题的解决方案时遇到了这个线程,该问题具有完全相同的要求,但适用于缺少 REVERSE
函数的不同类型的数据库。
在我的例子中,这是针对 OpenEdge (Progress) 数据库的,它的语法略有不同。这使我可以使用 INSTR
函数 most Oracle typed databases offer.
所以我想出了下面的代码:
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
属性.
为了完整起见,我将添加创建此标量函数所需的代码,以便可以像我在上述示例中那样使用它。并将完全按照 OP 的要求进行操作,作为 SQL 服务器的 LastIndexOf 方法。
-- 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
为所选字符编写了 2 个函数,1 到 return LastIndexOf。
CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(80), @pattern char)
RETURNS int
BEGIN
RETURN (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
END;
GO
and 1 to return 这个 LastIndexOf 之前的一个字符串。也许对某人有用。
CREATE FUNCTION dbo.StringBeforeLastIndex(@source nvarchar(80), @pattern char)
RETURNS nvarchar(80)
BEGIN
DECLARE @lastIndex int
SET @lastIndex = (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
RETURN SUBSTRING(@source, 0, @lastindex + 1)
-- +1 because index starts at 0, but length at 1, so to get up to 11th index, we need LENGTH 11+1=12
END;
GO
CREATE FUNCTION dbo.LastIndexOf(@text NTEXT, @delimiter NTEXT)
RETURNS INT
AS
BEGIN
IF (@text IS NULL) RETURN NULL;
IF (@delimiter IS NULL) RETURN NULL;
DECLARE @Text2 AS NVARCHAR(MAX) = @text;
DECLARE @Delimiter2 AS NVARCHAR(MAX) = @delimiter;
DECLARE @Index AS INT = CHARINDEX(REVERSE(@Delimiter2), REVERSE(@Text2));
IF (@Index < 1) RETURN 0;
DECLARE @ContentLength AS INT = (LEN('|' + @Text2 + '|') - 2);
DECLARE @DelimiterLength AS INT = (LEN('|' + @Delimiter2 + '|') - 2);
DECLARE @Result AS INT = (@ContentLength - @Index - @DelimiterLength + 2);
RETURN @Result;
END
- 允许使用多字符分隔符,例如“,”(逗号 space)。
- Returns 如果未找到分隔符,则返回 0。
- 出于舒适原因采用 NTEXT,因为 NVARCHAR(MAX) 隐含地转换为 NTEXT,但反之则不然。
- 正确处理带前导或尾部的分隔符 space!
试试这个。
drop table #temp
declare @brokername1 nvarchar(max)='indiabullssecurities,canmoney,indianivesh,acumencapitalmarket,sharekhan,edelweisscapital';
Create Table #temp
(
ID int identity(1,1) not null,
value varchar(100) not null
)
INSERT INTO #temp(value) SELECT value from STRING_SPLIT(@brokername1,',')
declare @id int;
set @id=(select max(id) from #temp)
--print @id
declare @results varchar(500)
select @results = coalesce(@results + ',', '') + convert(varchar(12),value)
from #temp where id<@id
order by id
print @results
尝试:
select LEN('tran van abc') + 1 - CHARINDEX(' ', REVERSE('tran van abc'))
因此,“ ”的最后一个索引是:9