Есть ли способ выполнить запрос внутри строкового значения (например, eval) в PostgreSQL? - PullRequest
12 голосов
/ 15 сентября 2011

Я хочу сделать так:

SELECT (EVAL 'SELECT 1') + 1;

Есть ли способ сделать это (EVAL) в PostgreSQL?

Ответы [ 5 ]

18 голосов
/ 15 сентября 2011

Если операторы, которые вы пытаетесь "eval", всегда возвращают один и тот же тип данных, вы можете написать функцию eval (), которая использует EXECUTE, упомянутый Grzegorz.

create or replace function eval(expression text) returns integer
as
$body$
declare
  result integer;
begin
  execute expression into result;
  return result;
end;
$body$
language plpgsql

Тогда вы могли бы сделать что-то вроде

SELECT eval('select 41') + 1;

Но этот подход не будет работать, если ваши динамические операторы возвращают что-то свое для каждого выражения, которое вы хотите оценить.

Также имейте в виду, что это создает огромный риск для безопасности, выполняя произвольные заявления. Если это проблема, зависит от вашей среды. Если это используется только в интерактивных сеансах SQL, то это не проблема.

2 голосов
/ 14 апреля 2016

Я бы пошел с типом текста , поскольку он более гибкий, используя операторы приведения типа, например, ::int, если необходимо:

create or replace function eval( sql  text ) returns text as $$
declare
  as_txt  text;
begin
  if  sql is null  then  return null ;  end if ;
  execute  sql  into  as_txt ;
  return  as_txt ;
end;
$$ language plpgsql
-- select eval('select 1')::int*2         -- => 2
-- select eval($$ select 'a'||1||'b' $$)  -- => a1b
-- select eval( null )                    -- => null

Я также добавил этои еще одну eval( sql, keys_arr, vals_arr ) функцию, поддерживающую некоторые пользовательские значения ключа замены, например, для удобных :param1 замен до postgres-utils

2 голосов
/ 14 апреля 2014

ПРИМЕЧАНИЯ

Синтаксис языка PLpgSQL имеет много способов сказать:

 Y := f(X);

Предложение EXECUTE предназначено только для "динамического выполнения" ( меньше производительности ),

 EXECUTE 'f(X)' INTO Y;     

Используйте Y := f(X); или SELECT для выполнения статических объявлений,

 SELECT f(X) INTO Y;

Использовать PERFORM для отметки при отмене результатов или для работы с пустыми возвратами:

 PERFORM f(X);     
1 голос
/ 15 сентября 2011

Я не уверен, подходит ли вам это, но PostgreSQL имеет оператор EXECUTE.

0 голосов
/ 17 апреля 2013

Хорошая идея. Вы можете изменить для выполнения прямых выражений:

create or replace function eval(expression text) returns integer
as
$body$
declare
  result integer;
begin
  execute 'SELECT ' || expression into result;
  return result;
end;
$body$
language plpgsql;

Для запуска просто наберите:

SELECT eval('2*2');
...