1

我得到了 Postgresql 8.4

我有一个用户表

user_id INT,
user_name VARCHAR(255),
user_email VARCHAR(255),
user_salt VARCHAR(255)

和2个功能:

一个SETOF

CREATE FUNCTION test ()
  RETURNS SETOF "user"
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      *
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

一个TABLE

CREATE FUNCTION test ()
  RETURNS TABLE (id INT, name VARCHAR, email VARCHAR)
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

SETOF列类型自动填充,但我无法设置列名以及在结果中选择哪些列。通过TABLE我可以切断user_前缀并设置确切的列名,但我必须手动设置列类型。

是否可以兼得两者的优点?

4

2 回答 2

2

PostgreSQL(以及一般的 SQL)中的类型处理是严格的。定义RETURN函数的类型可能很棘手。
简单的 SQL 解决方案

选择并重命名所有列:

SELECT * FROM t AS t(id, name, email, salt);

选择并重命名一些列:

SELECT user_id AS id, user_name AS name FROM t;

结合功能

如果你出于某种原因需要一个服务器端函数,你仍然可以将这些 SQL 特性与一个函数结合起来。给定一个t像你的问题中定义的表和这个简单的函数:

CREATE OR REPLACE FUNCTION f_test()
  RETURNS SETOF t AS
$func$
SELECT * FROM t  -- do stuff here
$func$ LANGUAGE sql STABLE;

仅重命名列(无需提供类型):

SELECT * FROM f_test() t(id, name, email, salt)

选择并重命名一些列:

SELECT user_id AS id, user_name AS name FROM f_test() t;

您可以将其与不同表上的各种不同函数结合使用:
重构 PL/pgSQL 函数以返回各种 SELECT 查询的输出

但我不完全确定你想在这里解决哪个问题。

旁白

于 2013-07-04T15:17:57.360 回答
1

我认为这在 pl/pgsql 中是不可能的,因为它在很大程度上取决于用户定义的类型。遗憾的是,这种语言对于类型自动检测来说不够智能......我认为我将使用的第一个可能的解决方案,它部分解决了问题,因为至少我不需要通过表列的类型更改手动重构每个函数.

1.)询问列类型的可能解决方案:

CREATE FUNCTION test ()
  RETURNS TABLE (id "user".user_id%TYPE, name "user".user_name%TYPE, email "user".user_email%TYPE)
AS
  $BODY$
  BEGIN
    return QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

这样至少类型不是多余的。不是最好的,但可以接受。

2.) 使用 SETOF RECORD 的可能解决方案:

CREATE FUNCTION test ()
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id AS id, "user".user_name AS name, "user".user_email AS email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

没有列类型定义列表,我收到以下错误:

错误:返回“记录”的函数需要列定义列表

所以我必须像这样使用它:

SELECT * FROM test() AS (id INT, name VARCHAR, email VARCHAR);

而不是这个:

SELECT * FROM test()

我通过 php 客户端获得了字符串中的每一列,因此列类型定义对我来说毫无用处......这个解决方案在没有列类型定义的情况下是最好的,但它是不可接受的。

可以使用类似于表的方法:

CREATE FUNCTION test (OUT id "user".user_id%TYPE, OUT name "user".user_name%TYPE, OUT email "user".user_email%TYPE)
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id, "user".user_name, "user".user_email
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

例如,我可以将所有内容设置为 TEXT:

CREATE FUNCTION test (OUT id TEXT, OUT name TEXT , OUT email TEXT )
  RETURNS SETOF RECORD
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      "user".user_id::TEXT , "user".user_name::TEXT , "user".user_email::TEXT 
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

这行得通,但这远非类型自动检测,它会导致大量冗余的文本转换器代码......

3.) 使用 recursors 的可能解决方案:

CREATE FUNCTION test ()
  RETURNS SETOF "user"
AS
  $BODY$
  DECLARE
    refc "user";
  BEGIN
    FOR refc IN 
      SELECT
        "user".user_id, "user".user_name, "user".user_email
      FROM
        "user"
    LOOP
        RETURN NEXT refc;
    END LOOP ;
    RETURN ;
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

这用空值填充缺少的列,我无法命名列,并且 sql 循环非常慢......所以这是不可接受的。

通过 refcursors 还有另一种方法:返回 refcursor 本身,但这是不可接受的,因为我不能将它用作普通变量,我必须给出一个字符串作为游标名称......顺便说一句,我没有设法使用 refcursor 本身结果是phpstorm。我得到 jdbc cursor not found 错误。也许我把名字设置错了,我不知道,我认为这不值得付出更多的努力。

于 2013-07-04T10:38:47.370 回答