postgresql - Postgres pl/pgsql 错误 : column "column_name" does not exist

标签 postgresql stored-procedures plpgsql

我有一个如下所示的存储过程,

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

最佳答案

您的函数可能如下所示:

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;

在 PostgreSQL 9.1 或更高版本中使用 format() 更简单

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

%I 转义标识符,例如 quote_ident()

要点:

  • 您遇到了不能为标识符使用参数的动态 SQL 的限制。您必须使用列名构建查询字符串,然后执行它。

  • 不过您可以使用值来做到这一点。我演示了 EXECUTEUSING 子句的使用。还要注意 quote_ident() 的使用: 防止 SQL 注入(inject)和某些语法错误。

  • 我还大大简化了您的功能。 [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);

关于postgresql - Postgres pl/pgsql 错误 : column "column_name" does not exist,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9510946/

相关文章:

mysql - 错误代码: 1064 in stored procedure update

php - 我应该使用 php 还是我的 sql 将数据插入表中

postgresql - 如何从 plpgsql 函数返回一个整数并回滚每个修改?

postgresql - 在函数中按列类型过滤行

ruby-on-rails - 尝试在两个模型之间进行 Rails 数据库关联/查询会引发错误

sql - 在 RETURNING 语句中使用记录作为函数参数

mysql - 寻找有关 Mysql 中存储过程调用的教程或说明

eclipse - 如何运行 PostgreSQL 函数

postgresql - 在 Postgres 中,表更改后如何重新验证 ("type-check") 函数和过程?

sql - 检索包含列组合的所有表名