Есть ли LastIndexOf в SQL Server?
Я пытаюсь разобрать значение из строки, которая включает в себя получение last index string. В настоящее время я делаю ужасный взлом, который включает в себя реверсирование строки:
SELECT REVERSE(SUBSTRING(REVERSE(DB_NAME()), 1,
CHARINDEX('_', REVERSE(DB_NAME()), 1) - 1))
Мне этот код почти нечитабельен. Я просто обновился до SQL Server 2016, и я надеюсь, что есть лучший способ.
Есть?
Ответы
Ответ 1
Если вы хотите все после последнего _
, используйте:
select right(db_name(), charindex('_', reverse(db_name()) + '_') - 1)
Если вы хотите все раньше, используйте left()
:
select left(db_name(), len(db_name()) - charindex('_', reverse(db_name()) + '_'))
Ответ 2
Нет, SQL-сервер не имеет LastIndexOf.
Это доступная строка функции
Но вы всегда можете создать свою собственную функцию
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
Ответ 3
После того, как у вас есть одна из разделяющих строк здесь, вы можете сделать это на основе набора так, как это.
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
Ответ 4
Я столкнулся с этим потоком, ища решение моей аналогичной проблемы, которое имело то же самое требование, но было для другого типа базы данных, в которой отсутствовала функция REVERSE
.
В моем случае это было для базы данных OpenEdge (Progress), которая имеет несколько иной синтаксис. Это сделало функцию INSTR
доступной для меня тем, что большинство баз данных, основанных на Oracle, предлагают.
Итак, я придумал следующий код:
SELECT
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', ''))) AS IndexOfLastSlash
FROM foo
Однако для моей конкретной ситуации (являющейся базой данных OpenEdge (Progress)) это не приводило к желаемому поведению, потому что замена символа пустым char давала ту же длину, что и исходная строка. Это не имеет большого значения для меня, но я смог обойти проблему с помощью кода ниже:
SELECT
INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/', 'XX')) - LENGTH(foo.filepath)) AS IndexOfLastSlash
FROM foo
Теперь я понимаю, что этот код не решит проблему для T-SQL, потому что нет альтернативы функции INSTR
, которая предлагает свойство Occurence
.
Чтобы быть осторожным, я добавлю код, необходимый для создания этой скалярной функции, поэтому его можно использовать так же, как в приведенных выше примерах. И будет делать то, что хотел OP, служит в качестве метода LastIndexOf для SQL Server.
-- 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
Ответ 5
Написал 2 функции, 1 для возврата LastIndexOf для выбранного символа.
CREATE FUNCTION dbo.LastIndexOf(@source nvarchar(20), @pattern char)
RETURNS int
BEGIN
RETURN (LEN(@source)) - CHARINDEX(@pattern, REVERSE(@source))
END;
GO
и 1, чтобы вернуть строку до этого LastIndexOf. Может быть, кому-то это будет полезно.
CREATE FUNCTION dbo.StringBeforeLastIndex(@source nvarchar(20), @pattern char)
RETURNS nvarchar(20)
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
Ответ 6
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
- Позволяет использовать многосимвольные разделители типа "," (запятая).
- Возвращает 0, если разделитель не найден.
- Принимает NTEXT для удобства, так как NVARCHAR (MAX) s неявно передаются в NTEXT, но не наоборот.
- Правильно обрабатывает разделители с ведущим или хвостовым пространством!