2013-07-04 77 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

如果您尝试将其作为“插入如果不存在”或“更新,插入(如果不存在)”的一部分来完成,请立即停止并阅读关于PostgreSQL的upsert。如果这不是你正在做的事情,也许编辑并解释你的真正目标是什么,因为很难想象像这样的功能有没有更好的方法来使用它。 –

回答

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'); 

由于毛毛回答您使用动态查询,所以即使你引用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)USING id INTO cnt;'或者对于没有'format'的旧版PostgreSQL版本,应该包装表格和'quote_ident'调用中的列名。 –

+0

+1为答案,然而@CraigRinger是正确的与他的顾虑,所以+1也是他。很高兴向OP展示如何进行动态查询和防止SQL注入,但我仍然认为编写这个确切的函数正在重新发明轮子。 – ElmoVanKielmo

+0

谢谢,我刚刚编辑答案。当我们可以使用'select exists(select * from my_table where my_column = my_value)'时,我看不到这个函数非常有用。 –