Функция динамического запроса Postgres

Мне нужно создать функцию, которая будет запускать запрос и возвращать результаты с именем таблицы, а имя столбца - это исправление, данное функции. В настоящее время у меня есть это:

CREATE OR REPLACE FUNCTION qa_scf(tname character varying, cname character varying)
RETURNS SETOF INT AS
$BODY$
BEGIN
RETURN QUERY SELECT * FROM tname WHERE cname !='AK' AND cname!='CK';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;

Это дает мне ошибку "Relation" tname "des not exist" при запуске. Я новичок в создании функций для Postgres, поэтому любая помощь приветствуется. Я чувствую, что возвращение int неверно, но я не знаю, что еще нужно сделать, чтобы он возвращал все столбцы для возвращаемых строк. Спасибо!

Ответ 1

Вы не можете использовать переменную вместо идентификатора. Вам нужно сделать это с помощью динамических запросов. Он будет выглядеть примерно так:

EXECUTE 'SELECT * FROM ' || quote_ident(tname) 
        || ' WHERE ' || quote_ident(cname) || ' NOT IN (''AK'',''CK'');'
INTO result_var;

Если вы используете PostgreSQL 9.1 или выше, вы можете использовать функцию format(), которая упрощает построение этой строки.

Ответ 2

Имена таблиц и столбцов не могут быть указаны как параметры или переменные без динамического построения строки для выполнения в качестве динамического оператора. Postgres имеет отличную вводную документацию о выполнении динамических утверждений. Важно правильно указывать идентификаторы и литералы с помощью quote_ident() или quote_literal(). Функция format() помогает очистить динамическую конструкцию sql-оператора. Поскольку вы объявляете функцию для возврата SETOF INTEGER, вы должны выбрать нужное целое поле, а не *.

CREATE OR REPLACE FUNCTION qa_scf(tname text, cname text)
RETURNS SETOF INTEGER AS
$BODY$
BEGIN
  RETURN QUERY EXECUTE format(
    'SELECT the_integer_field FROM %I WHERE %I NOT IN (%L,  %L)',
                                   tname,   cname,    'AK', 'CK'
  );
END;
$BODY$
LANGUAGE plpgsql;