【问题标题】:Postgres - is there a better way to prevent having to extract the interval in this case when function twice?Postgres - 有没有更好的方法来防止在这种情况下两次函数时必须提取间隔?
【发布时间】:2020-01-10 06:06:22
【问题描述】:

我在 postgres 中有以下函数,它们只接受 timestampz 并将记录的年龄作为类似于 Reddit 的字符串返回:

CREATE OR REPLACE FUNCTION ageFromTimestamp (t timestamp WITH TIME ZONE) 
RETURNS text as $$
DECLARE interval text;
BEGIN
    case 
    when extract(years from age(now(), t)) > 0 then interval = extract(years from age(now(), t)) || 'y';
    when extract(months from age(now(), t)) > 0 then interval = extract(months from age(now(), t)) || 'mo';
    when extract(days from age(now(), t)) > 0 then interval = extract(days from age(now(), t)) || 'd';
    when extract(hours from age(now(), t)) > 0 then interval = extract(hours from age(now(), t)) || 'h';
    when extract(minutes from age(now(), t)) > 0 then interval = extract(minutes from age(now(), t)) || 'm';
    when extract(seconds from age(now(), t)) > 0 then interval = ceil(extract(seconds from age(now(), t))) || 's';
    else interval = 'now';
    end case;
    return interval;
END;
$$ language 'plpgsql';

这工作得很好。我只是好奇是否有更好的方法来防止计算 extract(years from age(now(), t)) 两次?

我是 postgres 和 sql 的新手,所以学习新事物。

【问题讨论】:

  • 子查询将所有单独的片段提取到单独的字段中?

标签: sql postgresql stored-procedures plpgsql postgres-9.6


【解决方案1】:

使用查询怎么样?

select (case when a.y > 0 then a.y || 'y'
             when a.m > 0 then a.m || 'mo'
             . . . 
        end)
from (values (age(now()) as v(a) cross apply
     (values ( extract(year from v.a),
               extract(month from v.a),
               . . .
             )
     ) a(y, mo, . . .)

【讨论】:

  • 这不会提取所有内容吗?在我的示例代码中,它会在找到真实条件后立即跳出case when。在你的,它不会计算所有这些吗?
【解决方案2】:

从技术上讲,如果您将 CASE 更改为嵌套的 IF 并添加一个临时变量,应该是可能的,例如:

CREATE OR REPLACE FUNCTION ageFromTimestamp (t timestamp WITH TIME ZONE) 
RETURNS text as $$
DECLARE 
    interval text;
    temp double precision;
BEGIN
    temp = extract(years from age(now(), t));
    IF temp > 0 THEN
        interval = extract(years from age(now(), t)) || 'y';
    ELSE
        temp = extract(months from age(now(), t));
        IF temp > 0 THEN
            interval = extract(months from age(now(), t)) || 'mo';
        ELSE
            ...
        END IF;
    END IF;
    return interval;
END;
$$ language 'plpgsql';

但是,这种方法有一个缺点:根据您的要求,它意味着 7 个嵌套的IF,这使得该函数很难阅读和维护。 TBH,我会保持原样,除非您在使用时遇到严重的性能滞后。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-27
    • 2022-11-23
    • 2019-07-30
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    相关资源
    最近更新 更多