带有 CASE 的 Postgres 自定义函数

Posted

技术标签:

【中文标题】带有 CASE 的 Postgres 自定义函数【英文标题】:Postgres custom function with CASE 【发布时间】:2016-12-18 14:39:34 【问题描述】:

我有桌子watchers:

------------------------------------------
time_type | time_count | timestamp_created
------------------------------------------
  'hour'  |   1        |   2016-12-08 15:56:26.169614
  'hour'  |   13       |   ... 
  'day'   |   5        |   ...

我尝试根据time_typetime_count 值获取整数:

CREATE OR REPLACE FUNCTION af_calculate_range(tt text,tc  integer) RETURNS integer AS $$ 
            SELECT tt, CASE tt WHEN 'day' THEN tc * 60 * 60 
                               WHEN 'hour' THEN tc * 60
                       END
        FROM watchers;

          $$
    LANGUAGE SQL;

SELECT af_calculate_range(time_type, time_count) FROM watchers

但我得到一个错误:

ERROR:  return type mismatch in function declared to return integer  
DETAIL:  Final statement must return exactly one column. 
CONTEXT:  SQL function "af_calculate_range"
********** Error **********

用法:

SELECT * FROM watchers
WHERE  EXTRACT(EPOCH FROM now()) > (EXTRACT(EPOCH FROM timestamp_created) +
 af_calculate_range(time_type, time_count) )

如果 time_type = 'hour'time_count = 1 输出应该是 3600 秒。

我的例子有什么问题:

我用https://www.postgresql.org/docs/7.4/static/functions-conditional.html

和https://www.postgresql.org/docs/9.1/static/sql-createfunction.html

【问题讨论】:

您为什么要阅读完全过时版本 (7.4) 和已停产版本 (9.1) 的手册? 【参考方案1】:

一个函数只能返回一个值,所以你可能打算这样做:

CREATE OR REPLACE FUNCTION af_calculate_range(tt text, tc integer) RETURNS integer AS $$ 
        SELECT CASE WHEN tt = 'day' THEN tc * 60 * 60    -- return a (single) scalar 
                    WHEN tt = 'hour' THEN tc * 60
               END
        FROM watchers;
      $$
LANGUAGE SQL;

但正如@Mureinik 指出的那样,您甚至不需要做SELECT;直接使用CASE 表达式即可。

【讨论】:

【参考方案2】:

您不需要在那里进行查询,因为您将所有值传递给函数 - 只需返回 case 的值:

CREATE OR REPLACE FUNCTION af_calculate_range(tt TEXT, tc INTEGER) 
RETURNS INTEGER IMMUTABLE AS $$
BEGIN
    RETURN CASE tt WHEN 'day' THEN tc * 60 * 60
                   WHEN 'hour' THEN tc * 60
           END;
END;
$$
LANGUAGE PLPGSQL;

【讨论】:

【参考方案3】:

你太复杂了。改为存储interval

select now(), now() + interval '2 days';
              now              |           ?column?            
-------------------------------+-------------------------------
 2016-12-19 05:23:51.856137-02 | 2016-12-21 05:23:51.856137-02

create table watchers (
    the_interval interval,
    timestamp_created timestamp
);

insert into watchers (the_interval, timestamp_created) values
('1 hour', '2016-12-08 15:56:26.169614');

现在查询将是:

select * 
from watchers
where now() > timestamp_created + the_interval
;
 the_interval |     timestamp_created      
--------------+----------------------------
 01:00:00     | 2016-12-08 15:56:26.169614

【讨论】:

我是 sql 新手,它应该是什么样子? @snaggs:已编辑

以上是关于带有 CASE 的 Postgres 自定义函数的主要内容,如果未能解决你的问题,请参考以下文章

Postgres:将自定义类型从 Java 传递给 postgres 函数

自定义窗口函数忽略 Postgres 中的空值

如何将自定义类型数组传递给 Postgres 函数

从 postgres 函数映射自定义结果记录时面临问题

如何创建自定义函数来分析 postgres 中的表

我可以用 Postgres 定义一个自调整序列列吗?