plpgsql-通过返回结果集自动检测列类型
我拿到了Postgresql8.4 我有一个用户表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";
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语句中的列定义列表对我来说不好,因为它因每个函数而异。。。遗憾的是,我无法通过该项目选择数据库的版本。