13

我有一种情况,我想返回两个视图之间的连接。那是很多列。在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$
4

1 回答 1

34

消毒功能

您当前拥有的内容可以简化/清理为:

CREATE OR REPLACE FUNCTION func_a (username text = '', databaseobject text = '')
  RETURNS ????
  LANGUAGE plpgsql 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$;

BEGIN ... END您只需要在函数体中添加额外的实例来启动具有自己作用域的单独代码块,这很少需要。

标准的 SQL 连接运算符是||. +是您以前的供应商的“创造性”补充。

除非双引号,否则不要使用CaMeL 大小写标识符。最好不要使用它们请参阅:

varchar(4000)还针对 SQL Server 的特定限制量身定制。它在 Postgres 中没有特别的意义。仅varchar(4000)在您实际需要 4000 个字符的限制时使用。我只想使用- 除了我们text这里根本不需要任何变量,在简化函数之后。

如果您还没有使用过format()请在此处查阅手册

返回类型

现在,对于您的实际问题:动态查询的返回类型可能很棘手,因为 SQL 要求最迟在调用时声明它。如果您的数据库中有一个表或视图或复合类型已经与列定义列表匹配,您可以使用它:

CREATE FUNCTION foo()
  RETURNS SETOF my_view AS
...

否则,用(最简单的)拼写列定义列表RETURNS TABLE

CREATE FUNCTION foo()
  RETURNS TABLE (col1 int, col2 text, ...) AS
...

如果您正在制作行类型,则可以返回匿名记录:

CREATE FUNCTION foo()
  RETURNS SETOF record AS
...

但是你必须在每次调用时提供一个列定义列表,所以我几乎从不使用它。

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

CREATE OR REPLACE FUNCTION func_a(username text = '', databaseobject text = '')
  RETURNS TABLE(col1 int, col2 text, col3 date)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY EXECUTE
   format ($f$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$;

对于完全动态的查询,请考虑首先在客户端中构建查询,而不是使用函数。

您需要先了解基础知识:

然后还有更高级的多态类型选项,允许您在调用时传递返回类型。更多在最后一章:

于 2013-07-25T18:14:50.223 回答