我正在 Java 的 JDBC (Jaybird) 中测试 Firebird NUMERIC/DECIMAL 字段行为。
当使用FBResultSetMetaData
检查列属性时(例如使用ResultSet.getObject
方法进行SELECT * FROM NUMERICTEST
查询)我得到精度 (FBResultSetMetaData.getPrecision
) 和比例 (FBResultSetMetaData.getScale
) 与 Firebird 中表定义中声明的完全相同,例如
NUMERIC(3,2) field ... precision 3, scale 2
DECIMAL(3,2) field ... precision 3, scale 2
使用FBParameterMetaData
检查参数属性时(使用PreparedStatement.setObject
方法,例如INSERT INTO NUMERICTEST VALUES (?, ?)
查询)对于相同的字段,我得到不同的精度值(FBParameterMetaData.getPrecision
)和比例值(FBParameterMetaData.getScale
)。
NUMERIC(3,2) field ... precision 4, scale 2
DECIMAL(3,2) field ... precision 9, scale 2
我知道这些值以某种方式对应于这些字段的内部数据库存储类型(第一个示例中的 smallint
,第二个示例中的 integer
?)。
当 FBResultSetMetaData
和 FBParameterMetaData
与同一字段相关时,其行为不同的原因是什么?这是相当误导的。
Java 8 u 181、Jaybird 3.0.4、Firebird 2.5
最佳答案
问题是准备本身仅提供数字列的以下信息(参数和结果集列):
- 类型(
SQL_SHORT
、SQL_LONG
、SQL_INT64
、SQL_INT128
), - 子类型(0 表示
SMALLINT
/INTEGER
/BIGINT
/INT128
,1 表示NUMERIC
和 2 代表DECIMAL
, - 规模,
- 长度(以字节为单位)(2、4、8 或 16)。
换句话说,声明的精度不可用。
对于参数,无法知道与其比较或分配到的列的声明精度,因为 Firebird 没有提供允许发现实际精度的信息。因此,Jaybird 使用列类型的最大精度(即 SQL_SHORT
: 4、SQL_LONG
: 9、SQL_INT64
: 18 或 SQL_INT128
:38)。
对于结果集列,Firebird 在某些情况下可以提供基础列名称和表,Jaybird 使用此信息来查询元数据表以获取实际精度信息。此信息并不总是可用,例如计算/派生列或涉及 UNION
的查询列没有基础列名和表名。如果此信息不可用,Jaybird 将以与参数相同的方式进行估计。
此信息的精度没有真正的区别:即使声明为 DECIMAL(6,2)
(或 NUMERIC(6,2)
)的列也可以存储和返回最大精度为 9 的值(如果考虑到 SQL_LONG
是 32 位有符号整数,甚至可以为 10)。就 Firebird 中的所有意图和目的而言,DECIMAL(6,2)
实际上是 DECIMAL(9,2)
。但是,我们决定在该信息可用时提供实际声明的精度信息。
换句话说:Jaybird 尽可能精确,如果没有足够的信息,它会优雅地降级。
披露:我是 Jaybird 的开发者之一。
关于jdbc - Jaybird 中的 Firebird NUMERIC/DECIMAL 精度和比例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51468049/