如何使用减去天数的表达式添加生成的列?

Dol*_*hin 3 postgresql database-design computed-column interval

我在 PostgreSQL 13 中有这个表:

CREATE TABLE public."domain" (
    id int8 NOT NULL GENERATED ALWAYS AS IDENTITY,
    domain_name varchar NOT NULL,
    -- more columns
    expire_date timestamp NULL,
    days_before_trigger int4 NOT NULL DEFAULT 14
);
Run Code Online (Sandbox Code Playgroud)

现在我想添加一个生成的列notify_trigger_date,派生自expire_datedays_before_trigger,以记录我的网站 url ssl 证书到期日期。如何自动生成该列?
它看起来像这样:

notify_trigger_date = expire_date - 7 day
Run Code Online (Sandbox Code Playgroud)

我正在尝试像这样实现它:

ALTER TABLE "domain" ADD COLUMN notify_trigger_date timestamp 
    GENERATED ALWAYS AS ((expire_date::timestamp - '1 day')) STORED;
Run Code Online (Sandbox Code Playgroud)

我不知道如何1 day用天数替换days_before_trigger?此命令运行时出错:

SQL Error [22007]: ERROR: invalid input syntax for type timestamp: "1 day"
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能让它发挥作用?我已经阅读了 PostgreSQL 文档,但没有找到明确的解决方案。

Erw*_*ter 6

通常,最好的解决方案是根本不将功能相关值存储notify_trigger_date在表中。只会让桌子膨胀。对于timestampor timestamptz,请改用(非常便宜!)表达式:

expire_date - make_interval(days => days_before_trigger)
Run Code Online (Sandbox Code Playgroud)

或等价物(同样便宜):

expire_date - interval '1 day' * days_before_trigger
Run Code Online (Sandbox Code Playgroud)

适用于任何版本的 Postgres,同时make_interval()添加了 Postgres 10。

如果列expire_date是 typedate而不是timestamp,请使用更简单(甚至更便宜)的表达式:

expire_date - days_before_trigger
Run Code Online (Sandbox Code Playgroud)

你可以integer从 中减去date。有关的:

如果您需要(虚拟)列上的索引notify_trigger_date,我会建议一个表达式索引,如(假设date变体):

CREATE INDEX ON public."domain" ((expire_date - days_before_trigger)); -- parentheses required
Run Code Online (Sandbox Code Playgroud)

并在查询中重复相同的表达式:

SELECT * FROM "domain"
WHERE (expire_date - days_before_trigger) <= CURRENT_DATE;
Run Code Online (Sandbox Code Playgroud)

有关的:


Len*_*art 3

您需要在计算中包括 INTERVAL:

ALTER TABLE D ADD COLUMN notify_trigger_date timestamp
    GENERATED ALWAYS AS (expire_date - INTERVAL '1 day') STORED;
Run Code Online (Sandbox Code Playgroud)

如果天数存储在列中,您可以创建一个间隔,然后减去它。这是一个例子:

ALTER TABLE D ADD COLUMN notify_trigger_date date
    GENERATED ALWAYS AS (
        expire_date - make_interval(days => days_before_trigger)
    ) STORED;
Run Code Online (Sandbox Code Playgroud)