Позиция символа в строке

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
Akella
Сообщения: 95
Зарегистрирован: 13 дек 2005, 12:07

Позиция символа в строке

Сообщение Akella » 06 апр 2007, 11:26

В хранимке использую конструкцию вида

Код: Выделить всё

result = SUBSTRING(PARAM1 from 1 for ...);
вот вместо многоточия хотелось бы использовать что-то вида
Pos('.', PARAM1)-1 (из Delphi)
т.е. определить номер позиции точки.
Другими словами: в процедуру передаю строку вида "39.45.47.129" или "9.154.1280.1569", процедура должна вернуть всё, что ДО первой точки, т.е. "39" или соотвественно "9".
Как реализовать на PSQL функцию POS? Или в стандартных UDF есть что-то подобное. Я прекрасно понимаю, что можно решить проблему с пом. своей собственной UDF, но подумал, что в Firebird всё-таки должна быть реализована вроде бы такая маленькая, но нужная функция, как POS. поиск по форуму не помог.
Заранее благодарен.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 06 апр 2007, 11:37

Или в стандартных UDF есть что-то подобное.
Или. Или в нестандартных.
поиск по форуму не помог.
вот еще, я на форум буду класть перечень функций fbudf, rfunc и так далее? Такого перечня и на сайте нет.

Akella
Сообщения: 95
Зарегистрирован: 13 дек 2005, 12:07

Сообщение Akella » 06 апр 2007, 11:49

т.е. средствами стандартных UDF (поставляемых с FB) я такого не реализую?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 06 апр 2007, 12:00

Библиотека rFunc функция strpos.

Но можно и обойтись PSQL. (синтаксис FB2)

Код: Выделить всё

CREATE PROCEDURE POS(
    STR VARCHAR(100),
    STR1 VARCHAR(100))
RETURNS (
    P INTEGER)
AS
declare variable len_str integer;
declare variable len_str1 integer;
begin
  p = 0; if (str is null) then exit;
  len_str = char_length(str);
  len_str1 = char_length(str1);
  while (p <= len_str - len_str1) do begin
    p = p+1;
    if (substring(str from (:p) for len_str1) = str1) then exit;
  end
  p = 0;
end
Изменено: Оптимизировал процедуру по быстродействию
Последний раз редактировалось WildSery 06 апр 2007, 12:46, всего редактировалось 1 раз.

Akella
Сообщения: 95
Зарегистрирован: 13 дек 2005, 12:07

Сообщение Akella » 06 апр 2007, 12:09

Спасибище, Друг :wink:

Akella
Сообщения: 95
Зарегистрирован: 13 дек 2005, 12:07

Сообщение Akella » 06 апр 2007, 12:37

Немного переделав получил

Код: Выделить всё

CREATE PROCEDURE POS (
    str varchar(100),
    sub_str varchar(100))
returns (
    p integer)
as
begin
  p = 0;
  if (str is null) then exit;
  while (char_length(str) >= char_length(sub_str)) do begin
    p = p+1;

    if (substring(str from 1 for char_length(sub_str)) = sub_str) then begin
      suspend;
      exit;
    end
    str = substring(str from 2 for char_length(str));
  end
  p = 0;
end

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 06 апр 2007, 12:48

Akella писал(а):Немного переделав получил
Если тебе нужна селективная процедура, то SUSPEND нужно вставлять ещё в два места.
Посмотри ещё раз мой пост, я немного оптимизировал.

Akella
Сообщения: 95
Зарегистрирован: 13 дек 2005, 12:07

Сообщение Akella » 06 апр 2007, 13:34

Я понял, ещё после p = 0;

но ты не поставил suspend и после исправления своего сообщения, так и надо? Или почему ты не поставил suspend?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 06 апр 2007, 15:01

Ещё и перед EXIT в проверке на NULL, иначе процедура не вернёт значение.

У меня это "неселективная" процедура, из неё нельзя сделать SELECT * FROM POS(...);
Она вызывается EXECUTE PROCEDURE POS(...) RETURNING_VALUES P; для возврата значения в переменную P

Ответить