【问题标题】:Postgres function returning table not returning data in columnsPostgres函数返回表不返回列中的数据
【发布时间】:2013-01-15 17:32:20
【问题描述】:

我有一个返回表格的 Postgres 函数:

CREATE OR REPLACE FUNCTION testFunction() RETURNS TABLE(a int, b int) AS
$BODY$
DECLARE a int DEFAULT 0;
DECLARE b int DEFAULT 0;
BEGIN
CREATE TABLE tempTable AS SELECT a, b;
RETURN QUERY SELECT * FROM tempTable; 
DROP TABLE tempTable;
END;
$BODY$
LANGUAGE plpgsql;

此函数不以行和列的形式返回数据。相反,它将数据返回为:

(0,0)

这导致 Coldfusion cfquery 块在提取数据时出现问题。从该函数返回表时,如何获取行和列中的数据?换句话说:为什么 PL/pgSQL 函数不将数据作为列返回?

【问题讨论】:

  • 你为什么使用临时表?这是完全没有必要的,而且会使事情变慢而没有任何优势(您可以使用简单的 SQL 函数,这会使事情变得更快)

标签: sql postgresql plpgsql postgresql-9.1


【解决方案1】:

要获取单个列而不是行类型,请使用以下命令调用函数:

SELECT * FROM testfunction();

就像您从表中选择所有列一样。
还请考虑您的测试功能的这种审查形式:

CREATE OR REPLACE FUNCTION testfunction()
  RETURNS TABLE(a int, b int)
  LANGUAGE plpgsql AS
$func$
DECLARE
   _a int := 0;
   _b int := 0;
BEGIN
   CREATE TABLE tempTable AS SELECT _a, _b;
   RETURN QUERY SELECT * FROM tempTable;
   DROP TABLE tempTable;
END
$func$;

特别是:

DECLARE 关键字只需要一次。

避免在RETURNS TABLE (...) 子句中声明已经(隐式)声明为OUT 参数的参数。

不要在 Postgres 中使用不带引号的 CaMeL 大小写标识符。它可以工作,未加引号的标识符被转换为小写,但它可能导致令人困惑的错误。见:

示例中的临时表完全没用(可能过于简化)。给出的示例归结为:

CREATE OR REPLACE FUNCTION testfunction(OUT a int, OUT b int)
  LANGUAGE plpgsql AS
$func$
BEGIN
   a := 0;
   b := 0;
END
$func$;

【讨论】:

  • PostgreSQL 12 的 documentation 提倡额外的 RETURN; 明确说明您何时完成累积构建输出。
  • @JabroJacob:手册还指出(在所述位置):This restriction does not apply to functions with output parameters and functions returning void, however. In those cases a RETURN statement is automatically executed if the top-level block finishes. 您可以添加 RETURN 以明确表示,但这里是噪音。
  • 如果表超过10列怎么办?
  • @TheRealChx101:数字10有什么意义?
  • 只是一个没有意义的随机数。在您有很多列的情况下,我一直在寻找解决方案。我相信你已经在这里回答了这个问题:stackoverflow.com/a/8611675/1219213
【解决方案2】:

当然,您可以通过将函数调用放在 FROM 子句中来做到这一点,就像 Eric Brandstetter 正确回答一样。 但是,这有时会使 FROM 子句中已经包含其他内容的查询变得复杂。 要获取函数返回的各个列,可以使用以下语法:

SELECT (testfunction()).*

或者只获取名为“a”的列:

SELECT (testfunction()).a

将整个函数(包括输入值)放在括号中,后跟一个点和所需的列名或星号。

要获取函数返回的列名,您必须:

  • 查看源代码
  • 首先检查函数的结果,如下所示:SELECT * FROM testfunction()

输入值仍然可以来自FROM 子句。 只是为了说明这一点,考虑这个函数和测试数据:

CREATE FUNCTION funky(a integer, b integer)
RETURNS TABLE(x double precision, y double precision) AS $$
 SELECT a*random(), b*random();
$$ LANGUAGE SQL;

CREATE TABLE mytable(a integer, b integer);
INSERT INTO mytable
    SELECT generate_series(1,100), generate_series(101,200);

您可以调用函数“funky(a,b)”,而无需将其放在FROM 子句中:

SELECT (funky(mytable.a, mytable.b)).*
FROM mytable;

这将导致 2 列:

         x         |         y         
-------------------+-------------------
 0.202419687062502 |   55.417385618668
  1.97231830470264 |  63.3628275180236
  1.89781916560605 |  1.98870931006968
(...)

【讨论】:

  • SELECT 列表中直接取消集合返回的结果可能看起来像一个聪明的速记。但是,如果函数返回多个列(如手头的情况),则会导致函数被多次评估。更昂贵,可能会产生意想不到的副作用,甚至可以通过易失性功能产生令人惊讶的结果。通常,您不会想要这些。请参阅:stackoverflow.com/a/28853666/939860stackoverflow.com/a/18370271/939860
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 2016-03-20
相关资源
最近更新 更多