postgresql函数错误:列名不存在

Posted

技术标签:

【中文标题】postgresql函数错误:列名不存在【英文标题】:postgresql function error: column name does not exist 【发布时间】:2013-07-04 09:46:47 【问题描述】:

我已经实现了一个函数来检查一个值是否出现在特定表的特定行中:

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

为什么?

【问题讨论】:

如果您尝试将其作为“如果不存在则插入”或“更新,如果不存在则插入”类型的事情的一部分,请立即停止并阅读有关 PostgreSQL 上的 upsert 的信息。如果这不是你正在做的,也许编辑并解释你的真正目标是什么,因为很难想象这样的功能在没有更好的方法的情况下会有用。 【参考方案1】:

除了 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 ...,这在调试时非常方便。

【讨论】:

请不要使用直接字符串连接显示EXECUTE。它使函数成为 SQL 注入的向量。上面应该写成EXECUTE format('SELECT count(*) FROM %I WHERE %I = $1', table_name, table_column) USING id INTO cnt;,或者,对于没有format的旧PostgreSQL版本,应该在quote_ident调用中包装表和列名。 +1 为答案,但@CraigRinger 对他的担忧是正确的,所以也为他+1。很高兴向 OP 展示如何进行动态查询和防止 SQL 注入,但我仍然说编写这个确切的函数是在重新发明***。 谢谢,我刚刚编辑了答案。当我们可以使用select exists (select * from my_table where my_column=my_value) 时,我认为这个功能不是很有用。【参考方案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 而不是自己发明并没有什么不好 - 解决方案的性能将比使用随附的电池差得多... 希望这会有所帮助。祝你好运。

【讨论】:

以上是关于postgresql函数错误:列名不存在的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中,调用 PostgreSQL 函数,为啥我收到一个错误,通知该函数不存在?

postgreSQL 中不存在函数.. 为啥?

PostgreSQL之INSERT,DELETE,UPDATE

错误:PostgreSQL 中不存在列

PostgreSQL 函数不存在

PostgreSQL 错误的所有权