2013-07-04 3 views
1

я реализовал функцию, которая проверить, если значение отображается в конкретной строке конкретной таблицы:ошибка PostgreSQL функции: имя столбца не существует

CREATE FUNCTION check_if_if_exist(id INTEGER, table_name character(50), table_column character(20)) RETURNS BOOLEAN AS $$ 

DECLARE res BOOLEAN; 

BEGIN 
    SELECT table_column INTO res 
    FROM table_name 
    WHERE table_column = id; 

    RETURN res; 
END; 

$$ LANGUAGE plpgsql 

я уже создать и заполнить простую тестовую таблицу для попробовать эту функцию:

CREATE TABLE tab(f INTEGER); 

и я вызвать функцию как

SELECT check_if_exist(10, tab, f); 

но я происхожу в этой ошибке:

ERROR: column "prova" does not exist 
LINE 1: SELECT check_if_exist(10, tab, f); 
          ^


********** Error ********** 

ERROR: column "tab" does not exist 
SQL state: 42703 
Character: 27 

Почему?

+0

Если вы пытаетесь сделать это как часть типа «вставить, если не существует» или «обновить, вставить, если не существует», остановитесь сейчас и прочитайте о upsert на PostgreSQL. Если это не то, что вы делаете, возможно, отредактируйте и объясните, какова ваша настоящая цель, потому что трудно представить, как это работает, когда нет лучшего способа сделать это. –

ответ

2

Ваш код не имеет возможности работать - при работе с различными таблицами в PLPGSQL необходимо использовать динамические запросы, поэтому EXECUTE требуется - http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
Но прежде всего - нет ничего плохого в использовании PostgreSQL EXISTS - http://www.postgresql.org/docs/current/static/functions-subquery.html#AEN15284 вместо придумывать свои собственные - производительность вашего решения будет значительно хуже, чем использование включенных батарей ...
Надеюсь, это будет полезно. Удачи.

2

В дополнение к ответу Elmo вы должны быть осторожны с типами. У вас есть:

ERROR: column "tab" does not exist 

потому, что SQL-парсер не знают, как бороться с tab, который без кавычек. Ваш запрос должен быть как:

SELECT check_if_exist(10, 'tab', 'f'); 

Как Elmo ответил использовать динамический запрос, так что даже если вы цитируете tab вы получили сообщение об ошибке:

ERROR: relation "table_name" does not exist 

так что вы можете использовать EXECUTE, например:

CREATE OR REPLACE FUNCTION check_if_exist(id INTEGER, table_name varchar, table_column varchar) RETURNS BOOLEAN AS $$ 
    DECLARE 
     sql varchar; 
     cnt int; 
    BEGIN 
     sql := 'SELECT count(*) FROM ' || quote_ident(table_name) || ' WHERE ' || quote_ident(table_column) || '=$1'; 
     RAISE NOTICE 'sql %', sql; 
     EXECUTE sql USING id INTO cnt; 
     RETURN cnt > 0; 
    END; 
$$ LANGUAGE plpgsql 

Вы также можете использовать VARCHAR вместо character(N) в аргументах функции и использовать CREATE OR REPLACE FUNCTION ... вместо CREATE FUNCTION ..., что очень удобно при отладке.

+4

Пожалуйста, никогда не показывайте 'EXECUTE' с прямой конкатенацией строк. Это делает функцию вектором для SQL-инъекции. Вышеприведенное должно быть написано 'EXECUTE format ('SELECT count (*) FROM% I WHERE% I = $ 1', table_name, table_column) ИСПОЛЬЗОВАНИЕ id INTO cnt;' или, для более старых версий PostgreSQL без 'format', следует обернуть таблицу и имена столбцов в вызовах 'quote_ident'. –

+0

+1 за ответ, однако @CraigRinger прав со своими проблемами, поэтому +1 для него тоже. Приятно показать OP, как делать динамические запросы и предотвращать SQL-инъекцию, но я все же говорю, что написание этой точной функции - изобретать колесо. – ElmoVanKielmo

+0

Спасибо, я только что отредактировал ответ. Я не вижу эту функцию очень полезной, когда мы можем использовать 'select exists (выберите * from my_table where my_column = my_value)'. –

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