Postgres pl / pgsql ОШИБКА: столбец "имя-столбца" не существует - PullRequest
2 голосов
/ 01 марта 2012

У меня есть процедура storerd, как показано ниже,

CREATE FUNCTION select_transactions3(text, text, int)    
RETURNS SETOF transactions AS   
$body$   
DECLARE    
    rec transactions%ROWTYPE;  
BEGIN
    FOR rec IN (SELECT invoice_no, trans_date FROM transactions WHERE $1 = $2 limit $3  )    
    LOOP     
        RETURN NEXT rec;    
    END LOOP;  
END;   
$body$  
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;

, когда я выполняю запрос следующим образом:

select * from select_transactions3("invoice_no", '1103300105472',10);

или

select * from select_transactions3(invoice_no, '1103300105472',10);

он получает ошибку какэто: ОШИБКА: столбец "invoice_no" не существует

, но когда я пытаюсь выполнить с одним двоеточием, как это:

select * from select_transactions3('invoice_no', '1103300105472',10);

результат не является строкой.

как я могу получить такие данные:

  invoice_no   |       trans_date        
---------------+-------------------------
 1103300105472 | 2011-03-30 12:25:35.694

спасибо.

ОБНОВЛЕНИЕ: Если нам нужен определенный столбец таблицы, который мы хотим показать

CREATE FUNCTION select_to_transactions14(_col character varying, _val character varying, _limit int) 
RETURNS SETOF RECORD AS
$$
DECLARE
 rec record;
BEGIN
 FOR rec IN EXECUTE 'SELECT invoice_no, amount FROM transactions
                 WHERE  ' || _col || ' = $1 LIMIT $2' USING _val, _limit            LOOP
  RETURN NEXT rec;
 END LOOP;
END;
$$ LANGUAGE plpgsql;

чтобы получить результат:

SELECT * FROM select_to_transactions14( 'invoice_no', '1103300105472',1)
as ("invoice_no" varchar(125), "amount" numeric(12,2));

1 Ответ

6 голосов
/ 01 марта 2012

Ваша функция может выглядеть следующим образом:

CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)    
  RETURNS SETOF transactions AS   
$BODY$   
BEGIN

RETURN QUERY EXECUTE '
   SELECT *
   FROM   transactions
   WHERE  ' || quote_ident(_col) || ' = $1
   LIMIT  $2'
USING _val, _limit;

END;   
$BODY$  
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;

IN PostgreSQL 9.1 или более поздней, что проще с format()

...
RETURN QUERY EXECUTE format('
   SELECT *
   FROM   transactions
   WHERE  %I = $1
   LIMIT  $2', _col)
USING _val, _limit;
...

%I экранирует идентификаторы, такие как quote_ident().

Основные моменты:

  • Вы столкнулись с ограничением динамического SQL, из-за которого нельзя использовать параметры для идентификаторов.Вы должны построить строку запроса с именем столбца и , затем выполнить его.

  • Вы можете сделать это со значениями, хотя.Я демонстрирую использование предложения USING для EXECUTE.Также обратите внимание на использование quote_ident(): предотвращает внедрение SQL и некоторые синтаксические ошибки.

  • Я также значительно упростил вашу функцию.[RETURN QUERY EXECUTE][3] делает ваш код короче и быстрее.Не нужно зацикливаться, если все, что вы делаете, это возвращаете строку.

  • Я использую именованные IN параметры, поэтому вы не запутаетесь с $ -notation в строке запроса.$1 и $2 внутри строки запроса относятся к значениям, указанным в предложении USING, а не к входным параметрам.

  • Я изменяю на SELECT *, как у вас естьв любом случае вернуть всю строку, чтобы она соответствовала объявленному типу возврата.

  • Последнее, но не менее важное: обязательно учтите, что руководство говорит о функциях, объявленных SECURITY DEFINER.

ТИП ВОЗВРАТА

Если вы не хотите возвращать всю строку, есть одна удобная возможность:

CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)    
  RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...

Тогдавам не нужно предоставлять список определений столбцов при каждом вызове, и вы можете упростить до:

SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);
...