在PostgreSQL函数中声明并返回自定义类型

时间:2013-07-08 15:00:45

标签: sql function postgresql stored-procedures plpgsql

我找到了这篇文章:

http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

我试图用它作为我的功能的一个例子。 我从不同的表中选择不同的列,并尝试返回一组记录。

这是我的代码:

CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
  RETURNS SETOF widgetdetails AS
$BODY$
DECLARE
    rec widgetdetails %rowtype;

BEGIN

    FOR rec IN (

        SELECT widget_details.id, widget_details.contact_id, widget_details.priority, widget_owner.contact
        FROM widget_details, widget_owner
        WHERE widget_details.rid=widgetid 
        AND widget_details.active_yn = 't'
        AND widget_owner.id=widget_details.contact_id
        Order by widget_details.priority ASC)
    LOOP
       RETURN NEXT rec;
    END LOOP;
END;

$BODY$
  LANGUAGE plpgsql;

当我尝试编译此代码时,我得到错误类型" widgetdetails"不存在。根据wiki中的示例,我将逻辑更改为:

CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
  RETURNS SETOF widgetdetails AS
            'SELECT widget_details.id, widget_details.contact_id,      
            widget_details.priority, widget_owner.contact
        FROM widget_details, widget_owner
        WHERE widget_details.rid=widgetid 
        AND widget_details.active_yn = "t"
        AND widget_owner.id=widget_details.contact_id
        Order by widget_details.priority ASC'
$BODY$
DECLARE
    rec widgetdetails %rowtype;

BEGIN

    FOR rec IN (

        SELECT widget_details.id, widget_details.contact_id, widget_details.priority, widget_owner.contact
        FROM widget_details, widget_owner
        WHERE widget_details.rid=widgetid 
        AND widget_details.active_yn = 't'
        AND widget_owner.id=widget_details.contact_id
        Order by widget_details.priority ASC)
    LOOP
       RETURN NEXT rec;
    END LOOP;
END;

$BODY$
  LANGUAGE plpgsql;

它给我一个错误说:

  

ERROR: syntax error at or near "$BODY$

但我似乎无法看到/发现问题。

2 个答案:

答案 0 :(得分:3)

您尝试使用的语法对Postgres来说是陌生的。

您的代码比它需要的复杂得多。使用简单的SQL函数:

CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
  RETURNS TABLE (id int, contact_id int, priority int, contact text)
$func$
   SELECT d.id, d.contact_id, d.priority, o.contact
   FROM   widget_details d
   JOIN   widget_owner   o ON o.id = d.contact_id
   WHERE  d.rid = widgetid   -- where does widgetid come from?
   AND    d.active_yn = 't'
   ORDER  BY d.priority
$func$ LANGUAGE sql

对于这样一个简单的函数,你根本不需要plpgsql。请改用普通SQL function

使用RETURNS TABLE ()定义 ad-hoc行类型。由于您未提供表定义,因此我使用列类型进行了即兴创作。这也适用于plpgsql函数。

此外:

  • 使用合适的JOIN condition以提高可读性。

  • 使用表别名简化查询。

  • widget_details.active_yn使用数据类型boolean

布尔值

正如评论中所阐明的那样,它已经是一个布尔列。我建议使用TRUE / FALSE代替字符串文字't'/'f'进行数据输入 - 引用the manual about the boolean type

  

关键字TRUEFALSE是首选(符合SQL)用法。

WHERE子句中,每个表达式都被计算为boolean个结果。 TRUE符合条件,FALSENULL不符合条件。因此,对于boolean类型,您可以简化:

   AND    d.active_yn = TRUE

只是:

   AND    d.active_yn

答案 1 :(得分:2)

要使用自定义复合类型,您必须先使用CREATE TYPE创建它。

示例,松散地基于您的查询(使用实际数据类型进行更改):

CREATE TYPE widgetdetails AS (
  id INT,
  contact_id INT,
  widget_details INT,
  contact TEXT
);

只有在创建此类型后才能接受此声明:

DECLARE
    rec widgetdetails;
...

同样对于CREATE FUNCTION的语法,坚持你的第一个版本,第二次尝试有严重的问题,并没有帮助。