首页 > 解决方案 > 通过 jdbc 查询结果不正确

问题描述

通过 jdbc driver snowflake-jdbc-3.12.5.jar 从 Snowflake 查询值时,结果不正确。

  1. Snowflake 中的表定义:
create table test_dob(DOB DECIMAL(38,3),REL DECIMAL(38,5));
insert into test_dob values(0.99, 0.99);
  1. 通过 jdbc 驱动程序 snowflake-jdbc-3.12.5.jar 从表 'test_dob' 中查询值;
.....
Connection conn = DriverManager.getConnection("jdbc:snowflake://XXXXX.aws.snowflakecomputing.com?db=testdbu", "user", "password");

......
String sql = "select dob,rel from test_dob";
PreparedStatement stmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery();
  while (rs.next()) {
    for (int j = 1; j < rs.getMetaData().getColumnCount() + 1; j++) {
      //System.out.print(rs.getString(j) + ",");
      System.out.print(rs.getDouble(j) + ",");
  }
.......

查询结果如下:

 0.9900000095367432,0.99, 

可以得到第一列(“dob”)的查询值不正确,而第二列(“rel”)是正确的。

是驱动程序的错误吗?

标签: jdbcsnowflake-cloud-data-platform

解决方案


用于 SQL 类型的正确方法 是.ResultSetDECIMALResultSet::getBigDecimal(col)

相反,通过请求double类型ResultSet::getDouble(col),您正在强制转换基础数字表示。

鉴于 SQL 十进制/数字数据类型中的不同比例 (35),每种情况的转换double处理方式不同。对于较小的比例 ( 3),由于其有限的位宽,对传输的值使用 small-int 类型,并且它的双精度转换实际上使用了一个浮点类型,该类型在其下向上转换为双精度。对于较大的比例(5),使用常规整数并直接进行双精度转换。

jshell这是幕后发生的事情的纯 Java(通过)表示

~> jshell

jshell> short sv = 990; // with scale 3
jshell> (double) ((float) sv / (float) 1000l)
$n ==> 0.9900000095367432

jshell> int iv = 99000; // with scale 5
jshell> (double) ((double) iv / (double) 100000l)
$n ==> 0.99

是驱动程序的错误吗?

//案例中double所做的转换当然可以统一以改进行为,但除了用作测试示例之外,它不会解决问题。其他无法精确表示的键入数字将继续出现。byteshortint0.99DECIMALdouble

虽然由于用于表示每种类型的位,转换会产生不同的结果,但从驱动程序正确性的角度来看,两者都是有效的,因为通过要求 adouble代替 a BigDecimal,您表明您不需要精确表示正在被取回。

如果需要精确/正确性(例如处理货币或在某些科学应用中),请改用以下内容:

System.out.print(rs.getBigDecimal(j) + ",");

要了解floatdouble类型的有损精度,请阅读:浮点数学是否损坏?


推荐阅读