Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
Всем доброго дня!

Есть функция в VB Скрипт InStr, а в SQL Server есть аналог - функция PATINDEX.
А вот эквивалент InStrRev я не нашёл. Пришлось сочинить самому.
CREATE FUNCTION dbo.InStrRev
(@StringCheck Varchar(MAX), @StringMatch Varchar(MAX))
RETURNS Int
AS BEGIN
    DECLARE @Reverse AS Varchar(Max), @Result AS Int;

    IF @StringCheck Is Null OR @StringMatch Is Null
        RETURN 0;

    SELECT @Reverse = REVERSE(@StringCheck);
    IF @StringMatch NOT LIKE '%[%]%'
        SET @StringMatch = '%' + @StringMatch + '%';
    ELSE
        SET @StringMatch = '%' + REPLACE(REPLACE(LTRIM(RTRIM(REPLACE(REPLACE(@StringMatch,
            ' ', CHAR(1)), '%', ' '))), ' ', '%'), CHAR(1), ' ') + '%';

	IF PATINDEX(REVERSE(@StringMatch), @Reverse) = 0
        SET @Result = 0;
    ELSE
        SET @Result = LEN(@StringCheck)-PATINDEX(REVERSE(@StringMatch), @Reverse) +
            4 - LEN(@StringMatch);

	RETURN @Result;
END;


Хотелось бы узнать нет ли здесь подводных камней? А может предложите более оптимальное / лучшее решение чем этот?
1 июн 17, 12:46    [20530942]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
aleks2
Guest
1. Аналог InStr - CHARINDEX.
2. Что за продукт больного воображения? Проще надо быть.
1 июн 17, 13:15    [20531097]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
aleks2
1. Аналог InStr - CHARINDEX.
2. Что за продукт больного воображения? Проще надо быть.


Не понял Ваш ответ. Вообще-то мне нужен был аналог InStrRev. И что?
Ну вместо "PATINDEX" ОК, можно заменить на "CHARINDEX" в теле функции. Правда у "PATINDEX" можно использовать подстановочные символы (% _ []), вдруг пригодятся, поэтому "PATINDEX" чуть-чуть предпочтительнее.
1 июн 17, 14:26    [20531459]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5625
aleks2
1. Аналог InStr - CHARINDEX.
2. Что за продукт больного воображения? Проще надо быть.

3. Переделать на инлайновую функцию.
1 июн 17, 15:01    [20531609]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
iap
Member

Откуда: Москва
Сообщений: 46953
Если известен аналог функции для строки, то почему его не применить для поиска
перевёрнутой подстроки в перевёрнутой строке с помощью REVERSE()?
Останется только вернуть позицию найденного фрагмента, зная его длину и позицию с другого конца строки.
Разве это не делается одним SELECTом?
И разве это не даёт возможность сделать табличную инлайн функцию?
1 июн 17, 15:18    [20531701]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
Сон Веры Павловны
aleks2
1. Аналог InStr - CHARINDEX.
2. Что за продукт больного воображения? Проще надо быть.

3. Переделать на инлайновую функцию.

4. Принять тот факт, что LEN( x ) - PATINDEX( y, REVERSE( x ) ) + 1 все равно быстрее.
1 июн 17, 15:40    [20531839]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
iap
Если известен аналог функции для строки, то почему его не применить для поиска
перевёрнутой подстроки в перевёрнутой строке с помощью REVERSE()?
Останется только вернуть позицию найденного фрагмента, зная его длину и позицию с другого конца строки.
Разве это не делается одним SELECTом?
И разве это не даёт возможность сделать табличную инлайн функцию?

Не совсем понял Вашу идею. Можете привести пример?
1 июн 17, 16:27    [20532075]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
Руслан Дамирович
4. Принять тот факт, что LEN( x ) - PATINDEX( y, REVERSE( x ) ) + 1 все равно быстрее.


А если длина "y" больше одного символа, то результат будет не совсем корректный. Или я ошибаюсь?
1 июн 17, 16:32    [20532106]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
studieren
1. Не совсем понял Вашу идею. Можете привести пример?
2. А если длина "y" больше одного символа, то результат будет не совсем корректный. Или я ошибаюсь?

2. Вы думаете, ваша функция при длине больше > 1 и наличии LIKE синтаксиса точнее? :)
1. Можем
CREATE FUNCTION dbo.InStrRev(
  @StringCheck VARCHAR(MAX),
  @StringMatch VARCHAR(MAX)
)
RETURNS TABLE
AS 
  RETURN (
    SELECT
      [result] = CASE
        WHEN @StringCheck IS NULL OR @StringMatch IS NULL THEN 0
        WHEN PATINDEX( [pattern], [reverse] ) = 0 THEN 0
        ELSE LEN( [reverse] ) - PATINDEX( [pattern], [reverse] ) + 4 - LEN( [pattern] )
      END
    FROM (
      SELECT
        [pattern] = CASE
          WHEN @StringMatch NOT LIKE '%[%]%' THEN '%' + @StringMatch + '%'
          ELSE '%' + REPLACE(REPLACE(LTRIM(RTRIM(REPLACE(REPLACE(@StringMatch, ' ', CHAR(1)), '%', ' '))), ' ', '%'), CHAR(1), ' ') + '%'
        END,
        [reverse] = REVERSE( @StringCheck )
      ) ss
  )
GO
1 июн 17, 16:36    [20532144]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
iap
Member

Откуда: Москва
Сообщений: 46953
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;
Позиция последнего вхождения фрагмента '567' в исходной строке '125673456789'.
Или я всё неправильно понял?
Так сначала объясните на русском языке.
1 июн 17, 16:37    [20532152]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
Руслан Дамирович
Member

Откуда: Резиновая нерезиновая
Сообщений: 940
iap
... Позиция последнего вхождения фрагмента '567' в исходной строке '125673456789' ...

Ох, я только сейчас осознал, что искомую строку тоже нужно REVERSE!
1 июн 17, 16:41    [20532167]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
iap
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;
Позиция последнего вхождения фрагмента '567' в исходной строке '125673456789'.
Или я всё неправильно понял?
Так сначала объясните на русском языке.

Ах вот Вы что имели ввиду. Thank you!!!
Т.е. можно и без функции, просто добавить в запрос.
1 июн 17, 16:51    [20532218]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
iap
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;
Позиция последнего вхождения фрагмента '567' в исходной строке '125673456789'.
Или я всё неправильно понял?
Так сначала объясните на русском языке.

Правда есть 1 нюанс: если искомого текста нет, то скрипт начинает врать. Стало быть сначала надо будет проверить наличие искомого текста.
Попробовал вот так, начал врать.
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567!';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;

Возвращает 10, а не 0.
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567!';
SELECT CASE WHEN CHARINDEX(@StringMatch, @StringCheck) = 0 THEN 0
    ELSE LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2 END;
1 июн 17, 16:58    [20532241]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
iap
Member

Откуда: Москва
Сообщений: 46953
studieren
iap
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;

Позиция последнего вхождения фрагмента '567' в исходной строке '125673456789'.
Или я всё неправильно понял?
Так сначала объясните на русском языке.

Правда есть 1 нюанс: если искомого текста нет, то скрипт начинает врать. Стало быть сначала надо будет проверить наличие искомого текста.
Попробовал вот так, начал врать.
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567!';
SELECT LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2;


Возвращает 10, а не 0.
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567!';
SELECT CASE WHEN CHARINDEX(@StringMatch, @StringCheck) = 0 THEN 0
    ELSE LEN(@StringCheck)-LEN(@StringMatch)-CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck))+2 END;
DECLARE @StringCheck VARCHAR(100)='125673456789', @StringMatch VARCHAR(100)='567';
SELECT ISNULL(LEN(@StringCheck)-LEN(@StringMatch)-NULLIF(CHARINDEX(REVERSE(@StringMatch),REVERSE(@StringCheck)),0)+2,0);
1 июн 17, 20:58    [20533006]     Ответить | Цитировать Сообщить модератору
 Re: Функция похожая на InStrRev  [new]
studieren
Member

Откуда: Tashkent, Uzbekistan
Сообщений: 2834
iap,
Thank you very much!
2 июн 17, 03:28    [20533443]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить