Postgresql -函数返回多行错误

2w2cym1i  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(2)|浏览(154)

我在Stackoverflow的第一篇文章。我正试图“在职”学习Postgresql(12),似乎被一个相当简单的问题卡住了。我有一个12行的简单数据库。在一列(int)中有一个4位数字[代表一年]。我试图创建一个生成的always列,它取CurrentDate,减去前面提到的int列,得到一个Age(int)。
我错过了什么。肯定有一个简单的解决方案。
谢谢詹姆斯
经过几次失败的尝试,我意识到一个函数应该工作。下面是我创建的简单函数。该函数工作,但似乎返回了多于1行。我只需要Asset_Age generated always列来显示资产的年龄:[inservice是具有4位数的现有int列(例如1963年)]

--Function get_age

CREATE OR REPLACE FUNCTION amp.get_age()
RETURNS int
AS $CODE$
BEGIN
    RETURN extract (year from current_date)::int - inservice from amp.amp_pumpstations;
    
End
$CODE$
LANGUAGE PLPGSQL IMMUTABLE.

--------------

--create generated always column
ALTER TABLE IF EXISTS amp.amp_pumpstations
    ADD COLUMN asset_age integer GENERATED ALWAYS AS ((amp.get_age())) STORED;
    
-------------

ERROR:  query "SELECT extract(year from current_date)::int - inservice from amp.amp_pumpstations" returned more than one row
CONTEXT:  PL/pgSQL function amp.get_age() line 3 at RETURN
SQL state: 21000
wgxvkvu9

wgxvkvu91#

CURRENT_DATESTABLE function (value remains constant in a single statement), you should not use that in an IMMUTABLE function (function result is always the same for the same function arguments)。它今天可能“工作”,但明年你可能会有问题,因为功能可能已经“优化”了。通过扩展,您不能使用GENERATED ALWAYS列,因为这需要IMMUTABLE函数。
最重要的是,逻辑是错误的,因为asset_ageis calculated when the row is inserted in the table or its underlying columns updated,所以随着时间的推移,您的资产年龄去不同步。
您可以通过从表中删除列asset_age并创建一个在需要时计算值的视图来最轻松地解决这个问题:

CREATE VIEW amp.amp_pumpstations_age AS
    SELECT *, extract(year from current_date) - inservice AS asset_age
    FROM amp.amp_pumpstations;
o0lyfsai

o0lyfsai2#

这可以使用RETURN QUERY完成

CREATE OR REPLACE FUNCTION get_age()
RETURNS SETOF integer
AS $CODE$
BEGIN
    RETURN QUERY select extract (year from current_date)::int - inservice 
    from amp_pumpstations;
    
End
$CODE$
LANGUAGE PLPGSQL IMMUTABLE

Demo here

相关问题