PL/PgSQL:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换

Posted

技术标签:

【中文标题】PL/PgSQL:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换【英文标题】:PL/PgSQL: No function matches the given name and argument types. You might need to add explicit type casts 【发布时间】:2013-11-07 15:19:37 【问题描述】:

我正在尝试使用 PL/PgSQL 编写 dateadd() 函数。我希望能够添加从秒到年到日期/时间戳的任何内容。拼凑了一个功能(从在线获得的 sn-ps 等),并提出了这个“实现”:

CREATE OR REPLACE FUNCTION dateadd(diffType VARCHAR(15), incrementValue int, inputDate timestamp) RETURNS timestamp AS $$
DECLARE
   YEAR_CONST Char(15) := 'year';
   MONTH_CONST Char(15) := 'month';
   DAY_CONST Char(15) := 'day';
   HOUR_CONST Char(15) := 'hour';
   MIN_CONST Char(15) := 'min';
   SEC_CONST Char(15) := 'sec';

   dateTemp Date;
   intervals interval;
BEGIN
   IF lower($1) = lower(YEAR_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' year' as interval) into intervals;
   ELSEIF lower($1) = lower(MONTH_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' months' as interval) into intervals;
   ELSEIF lower($1) = lower(DAY_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' day' as interval) into intervals;
   ELSEIF lower($1) = lower(HOUR_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' hour' as interval) into intervals;
   ELSEIF lower($1) = lower(MIN_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' minute' as interval) into intervals;
   ELSEIF lower($1) = lower(SEC_CONST) THEN
       select cast(cast(incrementvalue as character varying) || ' second' as interval) into intervals;
   END IF;

   dateTemp:= inputdate + intervals;

   RETURN dateTemp;
END;
$$ IMMUTABLE LANGUAGE plpgsql;

但是,当我尝试使用该功能时,我收到以下错误:

template1=# select dateadd('hour', 1, getdate());
ERROR:  function dateadd(unknown, integer, timestamp with time zone) does not exist
LINE 1: select dateadd('hour', 1, getdate());
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
template1=# 

为什么PG找不到函数?

我在 Ubuntu 12.0.4 LTS 上运行 PG 9.3

【问题讨论】:

顺便说一句,这里的很多问题似乎都是在“模拟”来自 MS SQL Server 的函数。鉴于两者的行为永远不会完全一样,我不禁想到你的精力最好花在学习等效的 PostgreSQL 功能上。 @HomunculusReticulli 使用intervals := interval '1 year' * incrementvalue; 之类的东西可能会更好。更容易理解。 您是打算写一个替换相关 MS 函数的插件,还是只是为了获得一个高效的函数? @ErwinBrandstetter:我现在只想要一个替代品。一旦一切正常,我会担心优化。 请注意,这实际上永远不会作为直接替换(就在两个 DBMS 下工作相同的查询而言),因为 MS SQL 函数将裸词作为 datepart 参数,而这里它们需要被引用字符串。由于无论如何您都在更改调用代码,因此您可以将其更改为例如some_date + interval '2 months'(或some_date + '2 months'::interval;不知何故,我更喜欢这种语法,尽管它比 Postgres 更特殊)。 【参考方案1】:

你会自责的:出错的那一行(以及接下来的几行)和之前那一行的区别在于你不小心在错误的地方添加了一个下划线:

你有

HOUR_CONST_Char(15) := 'hour';

应该是

HOUR_CONST Char(15) := 'hour';

编辑

更新后的问题受到 Postgres 稍微挑剔的类型系统的影响:您的 getdate() 函数返回 timestamp with time zone,但您的 dateadd 接受 timestamp(即 timestamp without time zone)。使用 value::type 的 Postgres 简写,这应该可以工作 (SQLFiddle demo, using now() in place of getdate())

select dateadd('hour', 1, getdate()::timestamp);

但是,您还有其他一些奇怪的类型选择:

你的“常量”是Char(15),但不是15个字符长,所以会用空格填充;您可能应该使用VarChar(15),甚至只使用text(与MS SQL 不同,在Postgres 中,所有字符串都是动态存储在页外的,VarChar 本质上只是text,具有最大长度限制) . 您的中间变量(可能会被重构)的类型是 Date,而不是 Timestamp,因此会将输入截断为仅日期部分,没有时间。

最后,我将指出一项基本优化:您不需要lower() 您的常量,因为您已经知道它们是小写的。 :)

【讨论】:

哎呀!是时候再来一杯咖啡了;)!。除了那个错字之外,其余的逻辑都好吗?即它会做我想做的事吗? (即添加从秒到年的任何内容到日期或日期?) - 我对 PL/PgSQL 很陌生。谢谢 已修复,但功能仍无法正常工作.. 请查看更新后的问题。【参考方案2】:

它是 HOUR_CONST 和 Char(15) 之间的下划线 你应该输入“HOUR_CONST Char(15)”而不是“HOUR_CONST_Char(15)”

【讨论】:

以上是关于PL/PgSQL:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换的主要内容,如果未能解决你的问题,请参考以下文章

没有函数匹配给定的名称和参数类型。在带有 python 的 postgres 中

如何在 PL/pgSQL 中按行类型返回表

在 PL/pgSQL 函数中使用变量

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

PL/pgSQL 函数中的可选参数

没有运算符与给定名称和参数类型匹配。您可能需要添加显式类型转换。 -- Netbeans、Postgresql 8.4 和 Glassfish