【问题标题】:Issue when returning result in PostgreSQL function在 PostgreSQL 函数中返回结果时出现问题
【发布时间】:2014-04-21 22:55:52
【问题描述】:

我从 SQL Server 世界来到 PostgreSQL (9.0),在迁移存储过程/函数时遇到问题。该函数正在返回此错误消息:

SQLSTATE: 42601;
SQLERRM: query has no destination for result data

我需要同时返回查询结果和两个输出参数。查询结果表示为名为“paramName”和“value”的两列,每个选择查询有一行数据。

我需要做些什么来传递查询选择的列中的值以及不同结果集中的 OUT 参数,例如 Transact-SQL 可以完美地避免收到该错误消息?

这是 pl/pgsql 函数:

        CREATE OR REPLACE FUNCTION myplfunction(
            IN i_param1 character varying,
            IN i_param2 character varying,
            IN i_param3 character varying,
            IN i_param4 character varying,
            OUT o_call_status integer,
            OUT o_call_message character varying)
          RETURNS SETOF RECORD AS
        $BODY$
        DECLARE 
        val1 varchar;
        val2 varchar;
        val4 varchar;
       BEGIN
        -- A couple of IF THEN ommited here
        IF (v_solution_id IS NULL) THEN
            val1 := (Select column1 FROM tbl2 WHERE column2= i_param1);
            IF(val1 IS NULL) THEN
                o_call_status := 1005;
                o_call_message := column1 is not configured or invalid';
                RETURN;
            END IF;
        END IF;

            SELECT 'mycolumnname1' as paramName,mycolumn1 as value FROM tb1 
            WHERE column1 = val
            UNION ALL
            SELECT 'mycolumnname2' as paramName,mycolumn2 as value  FROM tb1 
            WHERE column1 = val
            UNION ALL
            SELECT 'mycolumnname3' as paramName,mycolumn3 as value  FROM tb2 
            WHERE column1 = val1 AND
            column4 = val4;      

            o_call_status := 0;
            o_call_message := '';
        RETURN;

            EXCEPTION WHEN OTHERS THEN 
                o_call_message := SQLERRM;
                o_call_status := SQLSTATE;
        end;

我得到的只是查询结果或结果集中的输出参数。我无法弄清楚如何在相同的函数响应中同时拥有两者。

更新:按照 Erwin 的建议使用游标实现:

       CREATE OR REPLACE FUNCTION myplfunction(
            IN i_param1 character varying,
            IN i_param2 character varying,
            IN i_param3 character varying,
            IN i_param4 character varying,
            OUT o_call_status integer,
            OUT o_call_message character varying)
          RETURNS refcursor AS
        $BODY$
        DECLARE 
        val1 varchar;
        val2 varchar;
        query_cursor refcursor;
       BEGIN
        -- A couple of IF THEN ommited here
        IF (v_solution_id IS NULL) THEN
            val1 := (Select column1 FROM tbl2 WHERE column2= i_param1);
            IF(val1 IS NULL) THEN
                o_call_status := 1005;
                o_call_message := column1 is not configured or invalid';
                RETURN;
            END IF;
        END IF;

            open  query_cursor for SELECT 'mycolumnname1' as paramName,
                                           mycolumn1 as value FROM tb1 
            WHERE column1 = val
            UNION ALL
            SELECT 'mycolumnname2' as paramName,mycolumn2 as value  FROM tb1 
            WHERE column1 = val
            UNION ALL
            SELECT 'mycolumnname3' as paramName,mycolumn3 as value  FROM tb2 
            WHERE column1 = val1 AND
            column4 = val4;     

            o_call_status := 0;
            o_call_message := '';
            RETURN query_cursor;

            EXCEPTION WHEN OTHERS THEN 
                o_call_message := SQLERRM;
                o_call_status := SQLSTATE;
       end;

select * from  myplfunction(param1,param2,param3,param4);

但我得到一个错误:

ERROR: function result type must be record because of OUT parameters
SQL state: 42P13

所以这意味着当我有 OUT 参数时我不能返回光标?

另外,IF THEN 子句中的return; 是否会按预期终止函数?

【问题讨论】:

  • 您至少需要提供整个功能。
  • 嗨@Bob 我刚开始时省略了几个IF THEN 就这样

标签: sql database postgresql plpgsql


【解决方案1】:

您的代码有许多错误。这应该有效:

CREATE OR REPLACE FUNCTION myplfunction(i_param1 text, i_param2 text
                                      , i_param3 text, i_param4 text)
  RETURNS TABLE(param_name text, param_value text) AS
$func$
DECLARE 
   val1 text;
   val2 text;
   o_call_status integer;   o_call_message text;   -- without purpose
BEGIN
   IF v_solution_id IS NULL THEN
      val1 := (SELECT column1 FROM tbl2 WHERE column2 = i_param1);
      IF val1 IS NULL THEN
         o_call_status  := 1005;
         o_call_message := 'column1 is not configured or invalid';
         -- I suggest this alternative:
         RAISE EXCEPTION 'column1 is not configured or invalid';
      END IF;
   END IF;

   RETURN QUERY
   SELECT 'mycolumnname1'::text, mycolumn1 FROM tb1 WHERE column1 = val -- val?
   UNION ALL
   SELECT 'mycolumnname2', mycolumn2 FROM tb1 WHERE column1 = val       -- val?
   UNION ALL
   SELECT 'mycolumnname3', mycolumn2 FROM tb2 WHERE column2 = val2 
                                              AND tb2paramName4 = i_val3;      
   o_call_status := 0;
   o_call_message := '';

   EXCEPTION WHEN OTHERS THEN 
      o_call_message := SQLERRM;
      o_call_status  := SQLSTATE;      -- without purpose
END
$func$ LANGUAGE plpgsql;
  • 主要问题的解决方案:使用RETURN QUERY 实际返回结果。没有目标的 SELECT 导致错误消息。

  • 多个草率错误:缺少单引号、多余逗号、缺少END IF;、多个WHERE 子句...

  • 您需要转换字符串文字以匹配声明的输出类型:'mycolumnname1'::text

  • val1 := column1 FROM tbl2 WHERE ...; 形式是可能的,但不鼓励使用。最好不要以这种方式混合 plpgsql 和 SQL 代码。使用我提供的替代方案(仅用于单个参数)或SELECT INTO

  • 我建议不要使用 CaMeL 大小写的标识符,即使这是允许的。除非双引号,否则它们将转换为小写。

【讨论】:

  • END IF 是提交问题时的错误,而不是实际功能中的错误。那么 o_call_message 和 o_call_status 是由于应用程序内部原因,我不能省略它们。
  • @Douglas:你也不能像显示的那样使用它们。
  • o_call_message 和 o_call_status 参数是出于应用程序内部原因,所以即使我想也不能省略它们。注意不要混合 plpgsql 和 SQL,我错过了。请检查更新的 plpgsql 代码并分享您的想法。
  • @Douglas:我记得之前回答过this question,如果要同时返回表两个变量,建议使用游标。但我再也找不到问题了。 (?)
  • 您说得对,我已将其删除以避免歧义并准确地重新表述我的担忧。当使用'Cursor'的推荐方法并使用FETCH ALL时,返回的结果是否可以被提取到SETOF'RECORD'类型中?
猜你喜欢
  • 1970-01-01
  • 2010-10-19
  • 2016-06-10
  • 2011-11-18
  • 2020-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多