简体   繁体   中英

Add a generated column in postgres using to_char and a date

I have a date column created_at in a postgres table. I have a long running query that groups the data by week, so part of the query is

(SELECT TO_CHAR(score.created_at, 'IYYY-IW') AS week, 
customer_id, AVG(score) AS avg_week_score FROM score

This is inefficient, and I would like to use the new generated column functionality in Postgres 12 to rather store a text version of each date as it is inserted.

I tried to run

alter table score add column gen_week text generated always as (TO_CHAR(created_at, 'IYYY-IW')) stored;

but got

ERROR:  generation expression is not immutable

I guessed that this has to do with the fact that created_at is dependent on locale, and especially timezone, so I tried

alter table score add column week_gen text generated always as (TO_CHAR(created_at::timestamptz at time zone 'UTC', 'IYYY-IW')) stored;

to make the timezone explicit, but this produces the same error.

Is there a way to make to_char behave immutably with a date object, or do I have to define my own immutable function based on to_char?

The problem is that to_char() could take modifies from the locale -- and functions either are or are not immutable.

You can do the same thing using extract() :

alter table score add column gen_week text generated always as 
    ((extract(isoyear from created_at) * 100 + extract(week from created_at))::text ) stored;

Actually, the above doesn't put the hyphen in, so:

alter table score add column gen_week text generated always as
    (extract(isoyear from created_at)::text || '-' || lpad(extract(week from created_at)::text, 2, '0')) stored;

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM