在INTERVAL列上定义范围CHECK(PostgreSQL)

时间:2014-02-01 15:02:08

标签: postgresql intervals check-constraints

我目前正在设计一个必须处理大量时态数据的数据库。因此,有很多列应该保持时间间隔类似的值。重要的是,这些值中的每一个都必须符合一组固定的数值范围。因此,创建数据库级约束来强制执行这些检查会很有意义(并且还提供一些有用的故障)。

首先我考虑使用BIGINT数据类型&将间隔存储为UNIX时间戳。这将允许我编写一些简单的CHECK约束,并且只需完成它。但是,调查PostgreSQL特定的INTERVAL数据类型似乎发现了一些非常有用的功能。此外,使用它可能在我的设计语义方面更有意义。

切换到INTERVAL之后我遇到的最大问题是,我似乎无法找到一种很好的统一方法来定义前面提到的CHECK约束。

以下是我正在尝试做的一个粗略的例子:

CREATE TABLE PURCHASE(
PURCHASE_ID             SERIAL,
PURCHASE_STATE_TYPE_ID  SMALLINT        NOT NULL,
CUSTOMER_ID             INTEGER         NOT NULL,
...
COOLINGOFF_PERIOD       INTERVAL(3)     NOT NULL,

CONSTRAINT PK_PURCHASE PRIMARY KEY(PURCHASE_ID),
CONSTRAINT FK_PURCHASE_PURCHASE_STATE_TYPE_ID FOREIGN KEY(PURCHASE_STATE_TYPE_ID) REFERENCES PURCHASE_STATE_TYPE(PURCHASE_STATE_TYPE_ID) ON UPDATE CASCADE,
...
CONSTRAINT CHK_PURCHASE_COOLINGOFF_PERIOD_IN_RANGE CHECK((EXTRACT(EPOCH FROM INTERVAL COOLINGOFF_PERIOD)) BETWEEN 0 AND 315400000)
...
);

在这种情况下,我们有CHK_PURCHASE_COOLINGOFF_PERIOD_IN_RANGE CHECK约束,它强制每个COOLINGOFF_PERIOD的{​​{1}}落在0到10年之间。

不幸的是,上面的DDL语句因语法错误而失败:PURCHASE

我在这里遗漏了什么吗?有没有一个漂亮而干净的(声明性)方式来实现这一点,还是应该回到使用ERROR: syntax error at or near "COOLINGOFF_PERIOD".呢?

1 个答案:

答案 0 :(得分:1)

从技术上讲,检查约束中的语法错误与此部分有关:

EPOCH FROM INTERVAL COOLINGOFF_PERIOD

这是不被接受的,因为在此上下文中INTERVAL意味着后跟文字,如INTERVAL '10 days'

无论如何,根据评论中的建议,甚至不需要EPOCH的翻译,更容易编写:

CREATE TABLE ... (
 ...
 COOLINGOFF_PERIOD       INTERVAL(3)     NOT NULL
    CHECK (COOLINGOFF_PERIOD between '0'::interval and '10 years'::interval)
 ...
);

有关所有详细信息和语法变体,请参阅文档中的Interval Input