问题描述
OceanBase 数据库中 Number 类型在建表时未指定精度,会将这列数据的数据类型读成Decimal(171,147),precision 是 171,scale 是 147。
以下例子以 OceanBase 数据库 V3.2.3 BP Hotfix4 (oceanbase-3.2.3.3-106040022022122222) 版本和 OceanBase Connector/J V2.4.3 版本为例进行说明。
在 IDE 软件中创建测试 Test 项目,测试代码如下。
```shell
@Test
public void test1() throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:oceanbase://xx.xx.xx.xx:xx/SYS?user=SYS@oracle&password=");
Statement stmt = conn.createStatement();
try {
stmt.execute("drop table t0");
} catch (SQLException e) {
// e.printStackTrace();
}
stmt.execute("CREATE TABLE fuyan2 (a NUMBER, b NUMBER(30),c NUMBER(38,9),d NUMBER(*,10));");
//
ResultSet rs = stmt.executeQuery("SELECT * FROM fuyan2;");
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
System.out.println(rsmd.getColumnName(i));
System.out.println("\tgetScale = " + rsmd.getScale(i) + "\tgetPrecision = " + rsmd.getPrecision(i) + "\tgetColumnDisplaySize = " + rsmd.getColumnDisplaySize(i));
System.out.println();
}
}
```
输出结果如下。
```shell
columnCount = 4
rsmd.getColumnName(i) = A
rsmd.getColumnName(i) = FUYAN2
rsmd.getScale(i) = 171
rsmd.getPrecision(i) = 147
rsmd.getColumnDisplaySize(i) = 149
rsmd.getColumnName(i) = B
rsmd.getColumnName(i) = FUYAN2
rsmd.getScale(i) = 0
rsmd.getPrecision(i) = 30
rsmd.getColumnDisplaySize(i) = 31
rsmd.getColumnName(i) = C
rsmd.getColumnName(i) = FUYAN2
rsmd.getScale(i) = 9
rsmd.getPrecision(i) = 38
rsmd.getColumnDisplaySize(i) = 40
rsmd.getColumnName(i) = D
rsmd.getColumnName(i) = FUYAN2
rsmd.getScale(i) = 10
rsmd.getPrecision(i) = 147
rsmd.getColumnDisplaySize(i) = 149
```
适用版本
OceanBase 数据库 V2.x 和 V3.x 版本。
问题原因
以下情况下可能会出现 precision_unknow_yet。precision_unknow_yet 的情况下,OceanBase 数据库返回的数据是存在问题的, 会返回171 这样的不正常值。
column 列未指定精度: 例如: create table t(c1 number); select c1 from t。
运算表达式返回的 number 数据 例如: select c1+1 from t;
Oracle 在处理未知精度的情况下, 会分为以下两类进行处理:
显示的指定 Number. 例如 cast(as number), to_number(c1) 等情况, Oracle 此时返回 -127 作为非法值
隐式的指定 Number。 例如, select c1+1 from t; Oracle 此时返回 0 作为非法值。
解决方法
在未知精度 (precision_unknow_yet )的情况下,将 precision 更正为了 0。
为了规避该问题,建议升级到已经修复的版本。目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP9 (oceanbase-3.2.3.3-109000182023071410) 及之后版本、V3.2.4 BP3 Hotfix1 (oceanbase-3.2.4.3-103010022023051317) 及之后版本。
规避方法
需要改变 schema 结构。
需要对运算后的表达式加一个 cast 指定精度, 如 cast (c1 as number(10,0)); 具体参考官方文档 cast 函数。