Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
plpgsql-通过返回结果集自动检测列类型_Sql_Postgresql_Types_Plpgsql - Fatal编程技术网

plpgsql-通过返回结果集自动检测列类型

plpgsql-通过返回结果集自动检测列类型,sql,postgresql,types,plpgsql,Sql,Postgresql,Types,Plpgsql,我拿到了Postgresql8.4 我有一个用户表 user_id INT, user_name VARCHAR(255), user_email VARCHAR(255), user_salt VARCHAR(255) 和2个功能: 带有设置的一个: CREATE FUNCTION test () RETURNS SETOF "user" AS $BODY$ BEGIN RETURN QUERY SELECT * FROM "user";

我拿到了Postgresql8.4

我有一个用户表

user_id INT,
user_name VARCHAR(255),
user_email VARCHAR(255),
user_salt VARCHAR(255)
和2个功能:

带有
设置的一个

CREATE FUNCTION test ()
  RETURNS SETOF "user"
AS
  $BODY$
  BEGIN
    RETURN QUERY SELECT
      *
    FROM
      "user";
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
带有
表格的一个

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
自动填充列类型,但我无法设置列名以及在结果中选择哪些列。通过
我可以切断
用户前缀
并设置准确的列名,但我必须手动设置列类型


有可能同时获得两者的优点吗?

我认为这在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;
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;
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;
这样,至少该类型不是冗余的。不是最好的,但可以接受

2.)记录集的可能解决方案:

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;
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;
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;
如果没有列类型定义列表,则出现以下错误:

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

所以我必须这样使用它:

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;
例如,我可以将所有内容设置为文本:

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.)使用refcursors的可能解决方案:

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;
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;
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本身,但这是不可接受的,因为我不能将其用作普通变量,我必须给出一个字符串作为游标名称。。。顺便说一句,我没有设法在phpstorm中使用refcursor本身。我发现jdbc游标未找到错误。也许我把名字设置错了,我不知道,我认为这不值得付出更多的努力。

PostgreSQL(以及一般SQL)中的类型处理是严格的。定义函数的
返回类型可能很棘手。
使用纯SQL有一些简单的解决方案:

选择并重命名所有列:

SELECT * FROM t AS t(id, name, email, salt);
选择并重命名某些列:

SELECT user_id AS id, user_name AS name FROM t;
SELECT user_id AS id, user_name AS name FROM f_test() 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 user_id AS id, user_name AS name FROM t;
SELECT user_id AS id, user_name AS name FROM f_test() t;
您可以将其与不同表上的各种不同函数结合使用:

但我不能完全确定你们在这里要解决的问题是什么

旁白
  • 不要引用语言名称
    plpgsql
    是一个标识符

  • 只能从表中选择的函数可以是。嵌套时重复调用可能有益

  • 一般来说,我建议升级到Postgres的当前版本。自8.4以来,这方面有了一些改进


感谢您的回答和建议!我的目标是仅使用SELECT*FROM func()调用函数,因为我不想在客户机中使用SQL模板,而只是使用数据库中存在的相同方法的代理。例如:$proxy->user\u read\u all()应该返回用户的结果集。所以select语句中的列定义列表对我来说不好,因为它因每个函数而异。。。遗憾的是,我无法通过该项目选择数据库的版本。