至于“可移植的创建表语句”:它从数据类型开始:无论布尔、整数或长数据类型是否属于任何 SQL 标准,我都非常欣赏这些类型。PostgreSql 支持这些数据类型,Oracle 不支持。具有讽刺意味的是,Oracle 在 PL/SQL 中支持布尔值,但不支持表中的数据类型。甚至表/列名等的长度在 Oracle 中也被限制为 30 个字符。因此,即使是最简单的“创建表”也不总是可移植的。
至于自动生成的主键:我不知道可移植的语法,所以我没有在“创建表”中定义它。当然,这只会延迟问题,并将其留给插入语句。本主题与另一个问题有关:以最有效的方式使用 JDBC 获取插入后生成的密钥。这在 Oracle 和 PostgreSql 之间有很大的不同,如果你曾经敢在 Oracle 中使用区分大小写的表/列名,那就不好笑了。
至于约束,我更喜欢在“创建表”之后的单独语句中添加它们。如果您在 Oracle 中使用 char(1) 和检查约束实现布尔数据类型,则约束集可能会有所不同,而 PostgreSql 直接支持此数据类型。
至于“标准”:一个例子
SQL99 standard: for SELECT DISTINCT, ORDER BY expressions must appear in select list
此消息来自 PostgreSql,Oracle 11g 没有抱怨。14年后,他们会改变吗?
一般来说,您仍然需要编写特定于数据库的代码。
至于您的结论:在我们的场景中,我们使用模型驱动方法实现了一个可移植的数据库应用程序。这个逻辑元数据由应用程序使用,不同的数据库类型有不同的后端。我们不使用任何 ORM,只使用“直接 SQL”,因为这简化了 SQL 语句的调优,并提供了对所有 SQL 功能的完全访问权限。我们编写了自己的库,后来我们发现关键思想与“Anorm”的这些思想相匹配。
好消息是,虽然有很多小烦恼,但它工作得很好,即使是复杂的查询。例如,窗口聚合函数非常可移植(row_number(),partition by)。您必须在 Oracle 上使用 listagg,而在 PostgreSql 上需要 string_agg。递归注释表表达式在 PostgreSql 中需要“with recursive”,Oracle 不喜欢。PostgreSql 在查询中支持“limit”和“offset”,你需要把它包装在Oracle 中。如果您在 Oracle 和 PostgreSql 中都使用 SQL 数组(将数组作为表中的列),它会让您发疯。Oracle 上有物化视图,但 PostgreSql 中不存在。令人惊讶的是,不仅可以用 Java 编写数据库存储过程,还可以用 Scala 编写数据库存储过程,这在 Oracle 和 PostgreSql 中运行得非常好。此列表不完整。但到目前为止,我们设法为任何“可移植性问题”找到了一个可接受的(= 快速)解决方案。
它有回报吗?在我们的场景中,有一个中央 Oracle 安装(RAC,读/写),但在每个应用程序服务器上都有分布式 PostgreSql 安装作为 localhost 数据库(只读)。这大大提高了性能和可扩展性,而不会造成成本损失。
如果你真的想只在数据库中解决它,有一种可能性:将任何东西放在存储过程中,用 Java/Scala 编写它们,并限制自己在应用程序中调用这些过程,并读取结果集。这当然只是将复杂性从应用程序层转移到数据库中,但是您接受了 hack :-)
如果您使用 Java 存储过程,触发器是相当标准化的。如果您的数据库、您的管理层、您的数据中心人员和您的同事都支持它。非技术/社会方面也需要考虑。我什至听说过不接受一般“左外连接”语法的数据库调优人。他们坚持使用“(+)”的Oracle方式。
因此,即使触发器 (PL/SQL) 和序列被标准化,也会有很多其他的事情需要考虑。
更新
至于返回生成的主键我只能从JDBC的角度来判断。
如果您使用Statement.getGeneratedKeys ,PostgreSql 会返回它(我认为这是正常的方式)。
Oracle 要求您在创建准备好的语句时指定要显式返回其值的(主键)列。这有效,但前提是您不使用区分大小写的表名。在这种情况下,您收到的只是一个误导性的ORA-00942:Oracle 的 JDBC 驱动程序中抛出的表或视图不存在:Oracle 的 JDBC 驱动程序中存在/存在错误,我还没有找到使用便携式获取值的方法JDBC 方法。因此,在插入后立即在同一事务中以额外的专有“select sequence.currVal from dual”为代价,您可以取回主键。在我们的案例中,额外的时间是可以接受的,我们比较了插入 100000 行的时间:PostgreSql 在第 10000 行之前更快,之后 Oracle 性能更好。
查看有关从 2008 年获取主键和
区分大小写的表名的错误报告的方法的 stackoverflow 问题
这个例子很好地说明了这些问题。通常 PostgreSql 会按照您期望的方式工作,但您可能必须为 Oracle 找到一种特殊的方式。