从PostgreSQL函数返回SETOF行

use*_*023 11 postgresql dynamic-sql plpgsql postgresql-9.2

我有一种情况,我想在两个视图之间返回连接.那是很多专栏.在sql server中很容易.但是在PostgreSQL中我加入时.我收到错误"需要列定义列表".

有什么方法可以绕过这个,我不想提供返回列的定义.

CREATE OR REPLACE FUNCTION functionA(username character varying DEFAULT ''::character varying, databaseobject character varying DEFAULT ''::character varying)
  RETURNS SETOF ???? AS
$BODY$
Declare 
SqlString varchar(4000) = '';
BEGIN
IF(UserName = '*') THEN
   Begin
   SqlString  := 'select * from view1 left join ' + databaseobject  + ' as view2 on view1.id = view2.id';
   End;
ELSE
    Begin
    SqlString := 'select * from view3 left join ' + databaseobject  + ' as view2 on view3.id = view2.id';
    End;
END IF; 
execute (SqlString  );
END;
$BODY$
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 28

消毒功能

本手册包含PL/pgSQL的所有基础知识.基本上,你所拥有的东西可以简化/消毒到:

CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
  RETURNS ???? AS
$func$
BEGIN

RETURN QUERY EXECUTE
format ('SELECT * FROM %s v1 LEFT JOIN %I v2 USING (id)'
       , CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END, databaseobject);

END
$func$  LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
  • 除了启动具有自己的作用域的单独代码块之外,您不需要BEGIN .. END函数体中的其他实例,这很少需要.

  • 标准的SQL连接运算符是||.+是您以前的供应商的"创意"添加.

  • 除非您对其进行双引号,否则请勿使用CaMeL案例标识符.最好不要使用它们:

  • varchar(4000)也适用于SQL Server的特定限制.这种数据类型在Postgres中没有任何性能优势.如果您确实需要4000个字符的限制,请仅使用它.我只想用text-除了我们不需要任何变量在这里,在我简化了功能.

  • 如果您尚未使用format(),请参阅此处的手册.

返回类型

现在,对于您的实际问题:动态查询的返回类型有点棘手,因为SQL要求函数返回定义良好的类型.如果数据库中的表或视图或复合类型已经与要返回的列定义列表匹配,则可以使用:

CREATE FUNCTION foo()
  RETURNS SETOF my_view AS
...
Run Code Online (Sandbox Code Playgroud)

如果您正在进行输入,则可以返回匿名记录:

CREATE FUNCTION foo()
  RETURNS SETOF record AS
...
Run Code Online (Sandbox Code Playgroud)

或提供(最简单)列定义列表RETURNS TABLE:

CREATE FUNCTION foo()
  RETURNS TABLE (col1 int, col2 text, ...) AS
...
Run Code Online (Sandbox Code Playgroud)

匿名记录的缺点:然后你必须提供每个调用的列定义列表,所以我几乎没有使用它.

我不会SELECT *开始使用.使用确定的列列表返回并相应地声明您的返回类型:

CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
  RETURNS TABLE(col1 int, col2 text, col3 date) AS
$func$
BEGIN

RETURN QUERY EXECUTE
format ('SELECT v1.col1, v1.col2, v2.col3
         FROM %s v1 LEFT JOIN %I v2 USING (id)$f$
       , CASE WHEN username = '*' THEN 'view1' ELSE 'view3' END, databaseobject);

END
$func$;
Run Code Online (Sandbox Code Playgroud)

对于完全动态的查询,我宁愿使用简单的SQL查询开始.不是功能.

有更多高级选项,但您可能需要先学习基础知识.


归档时间:

查看次数:

25114 次

最近记录:

8 年,3 月 前