Как создать функцию, возвращающую значение до первого нецифрового/десятичного символа

val функция должна возвращать числовое значение из строки до первого нецифрового символа, учитывая также первую десятичную точку:

val('1,2TEST')  should return 1.2
val('1,2,3')  should return 1.2
val('-1,2,3')  should return -1.2
val('')  shound return 0

Я старался

CREATE OR REPLACE FUNCTION public.VAL(value text)
  RETURNS numeric AS
$BODY$
SELECT coalesce(nullif('0'||substring(Translate($1,',','.'), '^-?[0-9]+\.?[0-9]*$'),''),'0')::numeric;
$BODY$ language sql immutable;

но если строка содержит символ %,

select val('1,2%')

возвращает 0.

Как заставить его вернуться на 1.2? Он должен работать, начиная с Postgres 9

Обновить

Gordon Fiddle для поддержки 9.5 возвращает null для нечисловой строки. Я решил это с помощью обертки:

CREATE OR REPLACE FUNCTION public.VALwithNull(value text)
  RETURNS numeric AS
$BODY$
SELECT    replace( (regexp_matches($1, '^-?[0-9]+,*[0-9]*'))[1], ',', '.') ::numeric;
$BODY$ language sql immutable;

CREATE OR REPLACE FUNCTION public.VAL(value text)
  RETURNS numeric AS
$BODY$
SELECT coalesce( VALwithNull($1) ,0) ;
$BODY$ language sql immutable;

select  val('') , val('test'), val('-77,7%')

Это лучший способ поддерживать 9.0+?


person Andrus    schedule 22.07.2020    source источник
comment
Postgres 9.0 уже давно устарел. Зачем вам поддерживать такую ​​устаревшую версию? (А версия 9.5 устаревает примерно через 6 месяцев)   -  person a_horse_with_no_name    schedule 22.07.2020
comment
9.0 используется в количестве серверов. Модернизировать его слишком много работы.   -  person Andrus    schedule 22.07.2020
comment
Поддержание работоспособности такого старого сервера требует гораздо больше работы, но, что более важно, сопряжено с гораздо большим риском. И чем дольше вы ждете (обязательное) обновление, тем сложнее оно будет.   -  person a_horse_with_no_name    schedule 22.07.2020
comment
Серверы 9.0 работают без каких-либо дополнительных действий. Насколько больше работы?   -  person Andrus    schedule 22.07.2020
comment
Вы не получаете никаких обновлений безопасности, поэтому вам нужно вкладывать время и деньги, чтобы обеспечить его безопасность. В зависимости от бизнеса, которым вы управляете, отсутствие обновлений безопасности может иметь серьезные последствия, если что-то пойдет не так. Вы также не получаете никаких исправлений для ошибок, которые потенциально могут повредить вашу базу данных, что может стоить вам времени и денег, если что-то пойдет не так. Вы также все еще используете Windows XP? Или ядро ​​Linux 2.4? При раннем обновлении обновление обычно намного менее трудозатратно, чем если бы вы ждали этого 10 лет или дольше.   -  person a_horse_with_no_name    schedule 22.07.2020
comment
@Andrus, потому что любые проблемы, с которыми вы столкнетесь, не будут исправлены. Потому что инструменты перестанут работать. Потому что, когда вы в конечном итоге будете вынуждены обновиться, вы обнаружите, что у вас нет прямого пути к новой версии, и вам придется мигрировать, переходя от одной промежуточной версии к другой.   -  person Panagiotis Kanavos    schedule 22.07.2020
comment
@Andrus, потому что в какой-то момент вы можете обнаружить, что застряли в устаревших инструментах, стеках и поставщиках. Как долго Npgsql будет поддерживать PostgreSQL 9.0? Будет ли их поставщик .NET 5 по-прежнему поддерживать его? Что делать, если вы застряли на старой версии .NET Core из-за устаревшей базы данных?   -  person Panagiotis Kanavos    schedule 22.07.2020
comment
@ Ангус, это тоже не придирки. У NpgSQL возникли проблемы с подключением к Amazon Redshift, поскольку он использовал устаревший API PostgreSQL 8.0. NgpSQL пытался установить определенные параметры при открытии соединения, которые были недоступны в Redshift/PostgreSQL 8.   -  person Panagiotis Kanavos    schedule 22.07.2020
comment
Ваш вопрос на самом деле является еще одним примером того, почему это требует больше работы: вы получили ответ, который работает для текущей версии, теперь вам нужно найти другое решение, которое работает с неподдерживаемыми версиями, чтобы имитировать функцию, которая была интегрирована в Postgres некоторое время назад.   -  person a_horse_with_no_name    schedule 22.07.2020


Ответы (1)


Я думаю, что это регулярное выражение делает то, что вы хотите:

replace( (regexp_match($1, '^-?[0-9]+,*[0-9]*') )[1], ',', '.')

Вот скрипт db‹›.

Вы также можете использовать regexp_matches(). Он делает то же самое в этом контексте.

person Gordon Linoff    schedule 22.07.2020
comment
Для скрипта '-1,2TEST' возвращается значение null . Как включить знак минус в начале строки? - person Andrus; 22.07.2020
comment
изменение версии на 9.5 в Fiddle приводит к ошибке. Как заставить его работать с Postgres 9.0+? Я обновил вопрос. - person Andrus; 22.07.2020
comment
@Андрус. . . Вместо этого используйте regexp_matches(): dbfiddle.uk/. - person Gordon Linoff; 22.07.2020
comment
Как заставить его вернуть 0, если строка не начинается с числа? Я попробовал select coalesce( replace((regexp_matches(str, '^[0-9]+,*[0-9]*'))[1], ',', '.'), '0') from (values ('T'),('')) v(str), но получил ошибку set-valued function called in context that cannot accept a set - person Andrus; 22.07.2020
comment
@Андрус. . . Это ответ на вопрос, который вы задали здесь. Если у вас есть другой вопрос, задайте его как новый вопрос. - person Gordon Linoff; 22.07.2020
comment
Я преобразовал null в 0, используя функцию-оболочку в обновленной части вопроса. Это лучший способ поддержки 9.0+? - person Andrus; 22.07.2020
comment
@Андрус. . . О, если вы просто хотите преобразовать NULL в 0, используйте coalesce(): coalesce(replace(regexp_match($1, '^-?[0-9]+,*[0-9]*'))[1], ',', '.'), '0'). - person Gordon Linoff; 22.07.2020
comment
Это выдает ошибку ERROR: syntax error at or near "[" . Похоже, это не поддерживается в 9.4 - person Andrus; 22.07.2020
comment
@Андрус. . . regexp_matches() есть в Postgres 9.4. - person Gordon Linoff; 22.07.2020
comment
regexp_matches() работало в 9.4, как показано в обновлении вопроса. Похоже, что индексатор массива [1] вызывает ошибку в 9.4. Является ли использование функции-оболочки, как показано в обновлении вопроса, лучшим способом решить эту проблему? - person Andrus; 22.07.2020
comment
@Андрус. . . Отсутствовала открывающая скобка. Это не должно было работать ни в одной версии. Код правильный в dbfiddle . . . а вот скрипт db, показывающий, что он работает в версии 9.4: db-fiddle.com /f/cygpqfJZQTUPxK4XT4cnyT/0. - person Gordon Linoff; 23.07.2020
comment
В 9.4 скрипка select coalesce( replace((regexp_matches(x, '^-?[0-9]+,*[0-9]*'))[1], ',', '.'), '0' ) from (values ('TEST')) v(x) по-прежнему возвращает error: set-valued function called in context that cannot accept a set. Как вернуть 0, если строка не начинается с цифры и знака -? - person Andrus; 23.07.2020