H2 vs PostgreSQL 生成的具有函数的列

Posted

技术标签:

【中文标题】H2 vs PostgreSQL 生成的具有函数的列【英文标题】:H2 vs PostgreSQL generated column with function 【发布时间】:2021-03-10 01:32:30 【问题描述】:

我正在尝试设置一个生成的列,该列在减去值时也会考虑空检查。在 PostgreSQL 中我做了:

ALTER TABLE session ADD COLUMN
    duration INTERVAL GENERATED ALWAYS AS age(time_ended, time_started) STORED;

H2 不支持年龄函数,所以我又一个补丁来创建函数别名:

CREATE ALIAS age FOR "net.agileb.config.H2Functions.age";

及对应的java代码:

package net.agileb.config;

import java.time.Duration;
import java.time.LocalDateTime;

public class H2Functions 
    public static Duration age(LocalDateTime endDate, LocalDateTime startDate) 
        return Duration.between(endDate, startDate);
    

我在 PostgreSQL 兼容模式下运行 H2:

    public:
      type: com.zaxxer.hikari.HikariDataSource
      url: jdbc:h2:mem:agileb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;
      driverClassName: org.h2.Driver

但 h2 仍然不喜欢生成列的语法:

SQL State  : 42001
Error Code : 42001
Message    : Syntax error in SQL statement "ALTER TABLE SESSION ADD COLUMN
    DURATION INTERVAL GENERATED[*] ALWAYS AS AGE(TIME_ENDED, TIME_STARTED) STORED"; expected "YEAR, MONTH, DAY, HOUR, MINUTE, SECOND"; SQL statement:
ALTER TABLE session ADD COLUMN
    duration INTERVAL GENERATED ALWAYS AS age(time_ended, time_started) STORED [42001-200]
Location   : db/migration/V1606395529__topic_calculated_duration_column.sql (/home/agilob/Projects/springowy/build/resources/main/db/migration/V1606395529__topic_calculated_duration_column.sql)
Line       : 3
Statement  : ALTER TABLE session ADD COLUMN
    duration INTERVAL GENERATED ALWAYS AS age(time_ended, time_started) STORED

我了解 H2 希望我使用特定间隔,例如 INTERVAL SECOND,生成为身份,STORED 关键字似乎不受支持。

有没有办法让这个查询在 PostgreSQL 和 H2 中工作?

【问题讨论】:

【参考方案1】:

在 PostgreSQL 和 H2 中无法对生成的列使用相同的语法。

    INTERVAL 没有区间限定符的数据类型是 PostgreSQL 的一个特性。包括 H2 在内的其他 DBMS 仅支持符合标准的区间,例如 INTERVAL YEARINTERVAL YEAR(3) TO MONTHINTERVAL DAY TO SECOND 等。希望您也可以在 PostgreSQL 中使用符合标准的区间数据类型,它们也受支持。但所有这些类型都是年月间隔或日间间隔。 YEAR 和/或 MONTH 字段的间隔不能有 DAYHOURMINUTESECOND 字段,反之亦然。如果你真的需要所有这些字段的混合区间,你可以只使用 PostgreSQL 及其分支。

    H2 1.4.200 仅支持带有 AS 关键字的生成列的非标准语法(即将推出的 H2 2.0 也支持标准语法 GENERATED ALWAYS AS)。 PostgreSQL 不支持 H2 的非标准语法。您可以从其当前来源构建 H2,以便在此处使用相同的标准语法。

    最大的问题是 PostgreSQL 出于某种奇怪的原因在生成列的定义末尾需要非标准的 STORED 子句,并且不接受符合标准的列定义。 H2等没有也不接受这个条款。

所以这里唯一的解决方案是对 PostgreSQL 和 H2 使用不同的 SQL。

【讨论】:

谢谢,我不知道这里是非标准的 postgres,而且 H2 与 AS 是非标准的。在这种情况下,我想我会将持续时间存储为int,以秒为单位。我宁愿避免为两个数据库使用不同的 SQL 补丁,而必须为 flyway 编写更多的 java 特定代码。

以上是关于H2 vs PostgreSQL 生成的具有函数的列的主要内容,如果未能解决你的问题,请参考以下文章

具有 Postgresql 部署的 Spring Boot MVC 应用程序在 Heroku 中失败

postgresql 兼容性中的语法错误 h2 数据库

通过 Spring Boot JPA + Postgresql + H2 执行间隔

使用 PostgreSQL 用户定义函数实现类似窗口函数的行为?

INNER JOIN 与 h2 数据库和 postgresql 数据库的区别

PostgreSQL:重用适用于虚拟表数据的函数代码