我正在用Java的JDBC(Jaybird)测试Firebird NUMERIC / DECIMAL字段的行为。
使用FBResultSetMetaData
检查列属性时(例如使用ResultSet.getObject
方法进行SELECT * FROM NUMERICTEST
查询),我得到了精度(FBResultSetMetaData.getPrecision
)和小数位数({{1 }})完全与Firebird中的表定义中声明的相同,例如
FBResultSetMetaData.getScale
使用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
与同一字段相关的行为不同的原因是什么?这是相当误导的。
Java 8 u 181,Jaybird 3.0.4,Firebird 2.5
答案 0 :(得分:2)
问题在于,prepare本身仅为数字列(参数和结果集列)提供以下信息:
SQL_SHORT
,SQL_LONG
,SQL_INT64
)SMALLINT
/ INTEGER
/ BIGINT
为0,NUMERIC
为1,DECIMAL
为2,换句话说,声明的精度不可用。
对于参数,由于Firebird不提供允许发现实际精度的信息,因此无法知道与之比较或分配给该列的声明精度。因此,Jaybird使用列类型的最大精度(即SQL_SHORT
:4,SQL_LONG
:9和SQL_INT64
:18)。
对于结果集列,Firebird可以在某些情况下提供基础列名称和表,而Jaybird使用此信息来查询元数据表以获取实际的精度信息。此信息并非始终可用,例如,计算/派生的列或涉及UNION
的查询的列没有基础列名和表名。如果此信息不可用,Jaybird将以与参数相同的方式进行估算。
此信息的精度没有什么实际区别:即使声明为DECIMAL(6,2)
(或NUMERIC(6,2)
)的列也可以存储和返回最大精度为9的值(即使考虑到事实,甚至为10) SQL_LONG
是32位有符号整数)。对于Firebird中的所有意图和目的,DECIMAL(6,2)
实际上是DECIMAL(9,2)
。但是,我们决定提供可用的实际声明精度信息。
换句话说:Jaybird尽可能地精确,如果没有足够的信息,则性能会下降。
披露:我是Jaybird的开发人员之一。