PostgreSQL & Division_by_zero исключение - PullRequest
1 голос
/ 11 января 2012

Я не совсем понимаю это правильно ... моя функция выглядит так:

create or replace function myfunc(integer, varchar(25), varchar(25), integer, integer) returns numeric as $$
declare var_return numeric;

begin

select sum(a+ b) / sum(a + b + c)
from mytable
where col1 = $1
and col2 = $2
and col3 = $3
and col4 between $4 AND $5
into var_return;

exception when division_by_zero then return 0.0;

return coalesce(var_return, 0.0);

end;

$$ language plpgsql;

Но когда я делаю select myfunc(123, 'foo', 'bar', 1, 10); я вижу:

ERROR:  control reached end of function without RETURN
CONTEXT:  PL/pgSQL function "myfunc"

Почему это происходит?Ясно, что я хочу поймать, когда оператор select встречает случай, когда a + b + c равен 0 и возвращает 0.

Ответы [ 3 ]

1 голос
/ 11 января 2012

Вы можете значительно упростить свою функцию:

CREATE OR REPLACE FUNCTION myfunc(int, varchar(25), varchar(25), int, int)
  RETURNS numeric AS
$BODY$

SELECT CASE WHEN abc = 0 THEN 0::numeric ELSE (ab/abc)::numeric END
FROM (
    SELECT sum(a + b) AS ab, sum(a + b + c) AS abc
    FROM   mytable
    WHERE  col1 = $1
    AND    col2 = $2
    AND    col3 = $3
    AND    col4 BETWEEN $4 AND $5
    ) x;

$BODY$ language SQL;

Основные баллы

  • Это language SQL, а не функция PL / pgSQL. Вы можете использовать любой из них, но в таком простом случае вы можете использовать более простой инструмент.

  • @ pilcrow точно установил причину вашей ошибки. Как вы понимаете, оператор RETURN является частью обработчика исключений и доступен только в случае возникновения исключения.

  • Если тип данных a, b, c должен быть integer или bigint, вы, вероятно, хотите привести к числовому до деления, или результаты будут приведены к целым числам. 1023 *

  • Используйте оператор CASE, чтобы избежать деления на ноль. Это на намного дешевле, чем обработка исключений.

1 голос
/ 11 января 2012

Предложение EXCEPTION относится ко всему блоку BEGIN и выполняется до конца. То есть Postgres понимает, что вы написали это:

create or replace function myfunc(...) returns ... as $$
  declare var_return numeric;

  begin
    select ...
    into var_return; -- but no RETURN statement in this block
  exception when division_by_zero then
    return 0.0;
    return coalesce(var_return, 0.0); -- this is part of the exception handler
  end;
$$ language plpgsql;

Переместите «RETURN COALESCE ...» выше линии ИСКЛЮЧЕНИЯ и повторите попытку.

0 голосов
/ 11 января 2012

Вы уверены, что обрабатываете правильное исключение?

Полагаю, у вас есть другое исключение.

См. Список исключений, которые вы можете перехватить.

Сначала я попробую (я всегда помещаю исключения в конце блока, легче для чтения.)

create or replace function myfunc(integer, varchar(25), varchar(25), integer, integer) returns numeric as $$
declare var_return numeric;

begin

   select sum(a+ b) / sum(a + b + c)
   from mytable
   where col1 = $1
   and col2 = $2
   and col3 = $3
   and col4 between $4 AND $5
   into var_return;

   return coalesce(var_return, 0.0);

   exception 
      when division_by_zero then 
         return 0.0;
      when others then 
         RAISE NOTICE 'caught others';
         return 0.0;



end;

$$ language plpgsql;
...