简单的 PL/pgSQL 函数的错误

Posted

技术标签:

【中文标题】简单的 PL/pgSQL 函数的错误【英文标题】:Errors with an easy PL/pgSQL Function 【发布时间】:2016-06-02 00:12:26 【问题描述】:

我正在尝试编写我的第一个 PL/pgSQL 函数。目前,它只是应该返回传递给它的值中的字符数。

CREATE OR REPLACE FUNCTION public.cents(money)
 RETURNS int
 LANGUAGE plpgsql
 LEAKPROOF
AS $function$
DECLARE
    new_price money;
    size int;
BEGIN
    size := char_length(money);
    RETURN size;
END;
$function$;

当我尝试使用 $66.66 进行测试时,我收到一个错误:

select cents($66.66);
ERROR:  syntax error at or near ".66"
LINE 1: select cents($66.66);
                        ^

如果我使用$66,我会得到一个不同的错误:

select cents($66);
ERROR:  there is no parameter $66
LINE 1: select cents($66);
                     ^

仅使用整数 66 给了我第三个错误:

select cents(66);
       ^

HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

我在这里做错了什么?

【问题讨论】:

【参考方案1】:

您确定要使用数据类型money 吗?考虑:

PostgreSQL: Which Datatype should be used for Currency?

如果您需要money 类型,请务必了解此类型的区域设置的作用。 Read the manual.

你不能输入没有单引号的文字(比如数字常量)——除非你强制转换它们,否则效率会很低。但这不是唯一的错误。你的函数会像这样工作:

CREATE OR REPLACE FUNCTION public.cents(_my_money_parameter money)
  RETURNS int AS
$func$
BEGIN
   RETURN char_length(_my_money_parameter::text);
END
$func$  LANGUAGE plpgsql LEAKPROOF;

呼叫:

SELECT public.cents(money '66.66');
SELECT public.cents('66.66'::money);
SELECT public.cents(66.66::money);

第一个调用变体是最有效的,但它取决于区域设置。我的示例中的 dot 在某些语言环境中被解释为千位分隔符并被忽略(而不是小数点)。

注意事项

您将money 视为函数体中的参数名称,但它只是数据类型。如果要使用参数名称,则必须像演示的那样声明它们。或者引用有位置引用的参数:$1$2等。

char_length() 需要一个字符数据类型,你不能将它用于数据类型money 而不进行强制转换。只是length() 是等效的。

如果包含美元符号,则字符串文字需要单引号:'$66.66' - 格式必须与您的语言环境设置相匹配才能适用于 money。 如果你只提供数字常量66,由于函数类型解析的规则,Postgres 将找不到带有money 参数的函数。详情:

Is there a way to disable function overloading in Postgres

首先阅读手册中的章节Constants。 继续CREATE FUNCTION 上的页面。

【讨论】:

【参考方案2】:

您需要在输入周围加上单引号:

SELECT cents('$66.66');

如果您的设置不允许这样做(仍然抛出错误),您可以尝试强制转换: SELECT cents('66.66'::float8::numeric::money);

请务必参考文档,因为它们提供了很好的概述: https://www.postgresql.org/docs/current/static/datatype-money.html

【讨论】:

您从手册中复制了演员表:::float8::numeric::money 但在这种情况下这是无稽之谈。它旨在转换数字 values 并且对于文字输入没有意义。除此之外,答案错过了问题中的大部分问题,并且忽略了使用输入 '$66.66' 警告可能的警告。不过,您指向手册的链接很有帮助,因此我将删除反对票。

以上是关于简单的 PL/pgSQL 函数的错误的主要内容,如果未能解决你的问题,请参考以下文章

PL/pgSQL 函数 + 客户端 lo_import

将数组传递给 PostgreSQL PL/pgSQL 函数

PL/pgSQL 中的“格式错误的数组文字”错误

Postgres 9.2 PL/pgSQL 循环简单更新

执行 SELECT 语句并丢弃 PL/pgSQL 中的结果

PL/pgSQL:删除(更新)与记录匹配的行