My first post in Stackoverflow. I am trying to learn Postgresql (12) "on the job" and seem to be stuck on a rather simple issue. I have a simple database with 12 rows. In one column (int) there is a 4-digit number [representing a year]. I am trying to create a generated always column that takes the Current Date, subtract the previously mentioned int column to get an Age (int).
What am I missing. There is surely a simple solution.
Thanks
James
After several failed attempts, I realize that a function should work. Here is the simple Function I created. The function works but seems to be returning more than 1 row. I just need the Asset_Age generated always column to show the age of the asset: [inservice is the existing int column that has the 4 digit (ex. 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
2
Answers
This can be done using
RETURN QUERY
Demo here
CURRENT_DATE
being aSTABLE
function (value remains constant in a single statement), you should not use that in anIMMUTABLE
function (function result is always the same for the same function arguments). It may "work" today but next year you likely have a problem because the function may have been "optimised". By extension, you cannot use aGENERATED ALWAYS
column because that needs anIMMUTABLE
function.On top of that, the logic is faulty in that the
asset_age
is calculated when the row is inserted in the table or its underlying columns updated so as time moves on your asset ages go out of sync.You can most easily solve your issue by dropping column
asset_age
from your table and create a view that calculates the value whenever you need it: