Найти индекс последнего появления подстроки с помощью T-SQL - PullRequest
112 голосов
/ 22 июня 2009

Есть ли простой способ найти индекс последнего вхождения строки с использованием SQL? Я использую SQL Server 2000 прямо сейчас. Мне в основном нужна функциональность, которую обеспечивает метод .NET System.String.LastIndexOf. Небольшой поиск в Google показал это - Функция для получения последнего индекса - но это не работает, если вы передаете выражение «текст» в столбце. Другие решения, найденные в других местах, работают только до тех пор, пока искомый текст имеет длину 1 символ.

Мне, вероятно, придется приготовить функцию. Если я сделаю это, я опубликую его здесь, чтобы вы, ребята, могли посмотреть на него и, возможно, воспользоваться им.

Ответы [ 21 ]

163 голосов
/ 22 июня 2009

Прямой путь? Нет, но я использовал обратное. В буквальном смысле.

В предыдущих подпрограммах, чтобы найти последнее вхождение данной строки, я использовал функцию 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?

Philip

95 голосов
/ 15 мая 2012

Самый простой способ это ....

REVERSE(SUBSTRING(REVERSE([field]),0,CHARINDEX('[expr]',REVERSE([field]))))
49 голосов
/ 04 декабря 2013

Если вы используете 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
28 голосов
/ 22 июня 2009

Вы ограничены небольшим списком функций для текстовых типов данных.

Все, что я могу предложить, это начать с PATINDEX, но работать в обратном направлении от DATALENGTH-1, DATALENGTH-2, DATALENGTH-3 и т. Д. До тех пор, пока вы не получите результат или не закончить до нуля (DATALENGTH-DATALENGTH)

Это действительно то, с чем SQL Server 2000 просто не может справиться.

Изменить для других ответов : REVERSE отсутствует в списке функций, которые можно использовать с текстовыми данными в SQL Server 2000

14 голосов
/ 03 марта 2016
DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'

SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt
7 голосов
/ 01 мая 2014

Это сработало очень хорошо для меня.

REVERSE(SUBSTRING(REVERSE([field]), CHARINDEX(REVERSE('[expr]'), REVERSE([field])) + DATALENGTH('[expr]'), DATALENGTH([field])))
7 голосов
/ 25 июня 2012

Старый, но все еще действительный вопрос, так что вот что я создал на основе информации, предоставленной другими здесь.

create function fnLastIndexOf(@text varChar(max),@char varchar(1))
returns int
as
begin
return len(@text) - charindex(@char, reverse(@text)) -1
end
6 голосов
/ 19 февраля 2013
REVERSE(SUBSTRING(REVERSE(ap_description),CHARINDEX('.',REVERSE(ap_description)),len(ap_description)))  

работал лучше для меня

4 голосов
/ 15 сентября 2010

Хм, я знаю, что это старый поток, но таблица подсчета может сделать это в 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 (Бесплатная регистрация, или просто используйте функцию «Не исправляйте меня» (http://www.bugmenot.com/view/sqlservercentral.com)).

)

* EDIT: удалено n <= LEN(TEXT_FIELD), поскольку вы не можете использовать LEN () для типа TEXT. Пока substring(...) = @delim остается, хотя результат все еще корректен.

2 голосов
/ 20 апреля 2013

Я понимаю, что это вопрос нескольких лет, но ...

На Access 2010 вы можете использовать InStrRev() для этого. Надеюсь, это поможет.

...