从PostgreSQL中的函数返回表类型

时间:2014-07-01 05:02:19

标签: postgresql plpgsql return-type

我有一个函数,其返回类型为TABLE,我想从我的表中获取某些列到我的功能的RETURN TABLE类型。当我执行该函数时,它没有给出错误但是没有返回任何记录,尽管它应该根据我的条件返回一些记录。 下面是我写的代码,有人可以告诉我哪里出错了吗?

CREATE OR REPLACE FUNCTION ccdb.fn_email_details_auto()
  RETURNS TABLE (code integer, area smallint, action smallint, flag smallint, ucount  integer, view_cnt integer) AS
$BODY$

DECLARE 
sec_col refcursor;
cnt integer;
sec_code ccdb.update_qtable%ROWTYPE;

BEGIN

SELECT COUNT(DISTINCT section_code)
INTO cnt
FROM ccdb.update_qtable
WHERE entry_time::date = now()::date - interval '1 day';

OPEN sec_col FOR
    SELECT * FROM ccdb.update_qtable WHERE entry_time::date = now()::date - interval '1 day';

FOR i IN 1..cnt
LOOP

FETCH sec_col INTO sec_code;

    PERFORM section_code, ddu_area, ddu_action, status_flag, ccdb_ucount, ccdb_view_cnt
FROM ccdb.update_qtable
WHERE entry_time::date = now()::date - interval '1 day' AND section_code =  sec_code.section_code
ORDER BY ddu_area, ddu_action;

END LOOP;

CLOSE sec_col;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

2 个答案:

答案 0 :(得分:2)

通过对我使用PERFORM的SELECT语句使用RETURN QUERY,我能够解决这个问题。 下面提到的查询帮助我实现了我的要求。

CREATE OR REPLACE FUNCTION ccdb.fn_email_details_auto()
  RETURNS TABLE (code integer, area smallint, action smallint, flag smallint, ucount integer, view_cnt integer) AS
$BODY$

DECLARE 
sec_col refcursor;
cnt integer;
sec_code ccdb.update_qtable%ROWTYPE;

BEGIN

SELECT COUNT(DISTINCT section_code)
INTO cnt
FROM ccdb.update_qtable
WHERE entry_time::date = now()::date - interval '1 day';

OPEN sec_col FOR
SELECT DISTINCT ON (section_code)* FROM ccdb.update_qtable WHERE entry_time::date = now()::date - interval '1 day';

FOR i IN 1..cnt
LOOP

FETCH sec_col INTO sec_code;

RETURN QUERY 
SELECT section_code, ddu_area, ddu_action, status_flag, ccdb_ucount, ccdb_view_cnt
FROM ccdb.update_qtable
WHERE entry_time::date = now()::date - interval '1 day' AND section_code = sec_code.section_code
ORDER BY ddu_area, ddu_action;

END LOOP;

CLOSE sec_col;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

答案 1 :(得分:2)

你的功能正在做很多空工作。

您可以使用带隐式光标的FOR loop进行简化,而不是使用更繁琐,更昂贵的显式光标 仔细看看事实证明你根本不需要这些。使用简单查询彻底简化。我把它包装成一个SQL函数:

CREATE OR REPLACE FUNCTION ccdb.fn_email_details_auto()
  RETURNS TABLE (code integer, area smallint, action smallint, flag smallint
               , ucount integer, view_cnt integer) AS
$func$

SELECT u.section_code, u.ddu_area, u.ddu_action, u.status_flag
     , u.ccdb_ucount, u.ccdb_view_cnt
FROM   ccdb.update_qtable u
WHERE  u.entry_time >= now()::date - 1
AND    u.entry_time <  now()::date        -- sargable!
ORDER  BY u.section_code, u.ddu_area, u.ddu_action;

$func$  LANGUAGE sql;

返回时应该更快。
另外,使用这个:

WHERE  u.entry_time >= now()::date - 1
AND    u.entry_time <  now()::date

而不是:

WHERE entry_time::date = now()::date - interval '1 day'

备选方案是sargable,可以使用entry_time上的普通索引,这对性能至关重要。