2012-06-06 2 views
1

У меня есть таблица со структурой, как это ...простой подстановки параметров в функции regexp_matches PostGreSQL

the_geom данные

geom1 data1+3000||data2+1000||data3+222 

geom2 data1+500||data2+900||data3+22232 

Я хочу создать функцию, которая возвращает записи по запросу пользователя.

Example: for data2, retrieve geom1,1000 and geom2, 900 

До сих пор я создал эту функцию (см ниже), который работает достаточно хорошо, но я столкнулся с проблемой замещения параметр ... (вы можете видеть, что я не в состоянии заменить «data2» за $ 1 в .. . Но да, я могу использовать $ 1 позже

regexp_matches(t::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer 

МОЕЙ фУНКЦИЮ

create or replace function get_counts(taxa varchar(100)) 

returns setof record 

as $$ 

SELECT t2.counter,t2.the_geom 

FROM (

    SELECT (regexp_matches(t.data::text, E'(data2[\+])([0-9]+)'::text)::text)[2]::integer as counter,the_geom 

    from (select the_geom,data from simple_inpn2 where data ~ $1::text) as t 

    ) t2 

    $$ 
language sql; 

SELECT get_counts('data2') will work **but we should be able to make this substitution**: 

regexp_matches(t::text, E'($1... instead of E'(data2.... 

Я думаю, что его больше вопроса syntaxis, как выполнение функции не дает никакой ошибки, просто интерпретирует $ 1 в виде строки и не дает никакого результата

спасибо заранее,

+0

Итак, вы хотите использовать параметр '$ 1' для своей функции вместо части' data2' вашего '(data2 [\ +]) ([0-9] +)' regex? –

+0

да, есть. Как я уже сказал, если я прямо поставил .. regexp_matches (t.data::text, E '($ 1 ... буквально интерпретируется ($ 1), не давая результата. Я пробовал несколько вариантов синтаксиса без успеха. – user1249791

ответ

1

E'$1' является строковым (с использованием синтаксиса escape string), содержащий знак доллара, за которым следует один. Необязательный $1 - это первый параметр вашей функции. Так что это:

regexp_matches(t, E'($1[\+])([0-9]+)'))[2]::integer 

как вы нашли, не интерполировать $1 с первым параметром функции.

Регулярное выражение - это просто строка, строка с внутренней структурой, но все еще только строка. Если вы знаете, что $1 будет нормальным словом, то вы могли бы сказать:

regexp_matches(t, E'(' || $1 || E'[\+])([0-9]+)'))[2]::integer 

, чтобы вставить строки вместе в подходящее регулярное выражение. Тем не менее, лучше быть немного параноиком, рано или поздно кто-то будет называть вашу функцию строкой вроде 'ha ha (', поэтому вы должны быть готовы к этому. Самый простой способ, что я могу думать, чтобы добавить произвольную строку в регулярное выражение, чтобы избежать всех персонажей без слов:

-- Don't forget to escape the escaped escapes! Hence all the backslashes. 
str := regexp_replace($1, E'(\\W)', E'\\\\\\1', 'g'); 

, а затем вставьте str в регулярное выражение, как описано выше:

regexp_matches(t, E'(' || str || E'[\+])([0-9]+)'))[2]::integer 

или лучше, построить регулярное выражение вне regexp_matches сократить на вложенных скобок:

re := E'(' || str || E'[\+])([0-9]+)'; 
-- ... 
select regexp_matches(t, re)[2]::integer ... 

PostgreSQL не имеет Perl's \Q...\E и (?q) metasyntax применяется до конца регулярного выражения, поэтому я не могу придумать какой-либо лучший способ вставить произвольную строку в середину регулярного выражения как литерал без регулярного выражения, чем для того, чтобы избежать всего и позволить PostgreSQL разобраться в нем.

Используя эту технику, мы можем сделать что-то вроде:

=> do $$ 
    declare 
     m text[]; 
     s text; 
     r text; 
    begin 
     s = E'''{ha)?'; 
     r = regexp_replace(s, E'(\\W)', E'\\\\\\1', 'g'); 
     r = '(ha' || r || ')'; 
     raise notice '%', r; 
     select regexp_matches(E'ha''{ha)?', r) into m; 
     raise notice '%', m[1]; 
    end$$; 

и получить ожидаемый

NOTICE: ha'{ha)? 

выход. Но если оставить в regexp_replace вытекающее шаг, вы просто получите ошибку

invalid regular expression: parentheses() not balanced 

.

В стороне, я не думаю, что вам нужно все, что кастинг, поэтому я удалил его. Регулярные выражения и экранирование достаточно шумные, нет необходимости бросать в смесь кучу двоеточий. Кроме того, я не знаю, что для вашего standard_conforming_strings установлено или для какой версии PostgreSQL вы используете, поэтому я поехал со строками E'' везде. Вы также захотите переключить свою процедуру на PL/pgSQL (language plpgsql), чтобы упростить экранирование.

Смежные вопросы