在 Oracle 云数据库中假装为 NULL 的 NUMBERS

NUMBERS pretending to be NULL in Oracle Cloud Database

提问人:Henning 提问时间:8/9/2023 最后编辑:Henning 更新时间:9/19/2023 访问量:60

问:

我们的 Delphi 应用程序使用 19.18.0.0.0 Oracle 客户端连接到 Oracle 云中的 Oracle 19c 数据库。 由于几个月后,每当它将一些特殊数字插入数字列时,该字段对所有其他应用程序来说看起来都是 NULL。 由应用程序本身选择的数字似乎是正确的。 当您使用 Oracle SQL Developer 或任何其他应用程序执行类似操作时,乐趣就开始了:

-- Creating test table
CREATE TABLE TEST (
    TOOL NUMBER(1),
    COL1 NUMBER(15,2)
);


-- INSERTS performed by the application
INSERT INTO TEST (TOOL, COL1) VALUES (1, NULL);
INSERT INTO TEST (TOOL, COL1) VALUES (1, 196);
INSERT INTO TEST (TOOL, COL1) VALUES (1, 197);
INSERT INTO TEST (TOOL, COL1) VALUES (1, 198);
INSERT INTO TEST (TOOL, COL1) VALUES (1, 199);
INSERT INTO TEST (TOOL, COL1) VALUES (1, 200);
COMMIT;


-- INSERTS performed by SQL Developer
INSERT INTO TEST (TOOL, COL1) VALUES (2, NULL);
INSERT INTO TEST (TOOL, COL1) VALUES (2, 196);
INSERT INTO TEST (TOOL, COL1) VALUES (2, 197);
INSERT INTO TEST (TOOL, COL1) VALUES (2, 198);
INSERT INTO TEST (TOOL, COL1) VALUES (2, 199);
INSERT INTO TEST (TOOL, COL1) VALUES (2, 200);
COMMIT;


-- SELECT performed by the application
SELECT TOOL, COL1, COL1 + 1 COL1P1, DUMP(COL1, 16) DMP FROM TEST WHERE (COL1 IS NOT NULL);

 TOOL  |  COL1  | COL1P1 | DMP
------------------------------------------------
    1  |   196  |    197 | Typ=2 Len=3: c2,2,61
    1  |   197  |    198 | Typ=2 Len=3: c2,2,62
    1  |   198  |    199 | Typ=2 Len=3: c2,2,63
    1  |   199  |    200 | Typ=2 Len=3: c2,2,64
    1  |   200  |    201 | Typ=2 Len=2: c2,3
    2  |   196  |    197 | Typ=2 Len=3: c2,2,61
    2  |   197  |    198 | Typ=2 Len=3: c2,2,62
    2  |   198  |    199 | Typ=2 Len=3: c2,2,63
    2  |   199  |    200 | Typ=2 Len=3: c2,2,64
    2  |   200  |    201 | Typ=2 Len=2: c2,3

SELECT TOOL, COL1, COL1 + 1 COL1P1, DUMP(COL1, 16) DMP FROM TEST WHERE (COL1 IS NULL);

 TOOL  |  COL1  | COL1P1 | DMP
--------------------------------
    1  |  NULL  |   NULL | NULL
    2  |  NULL  |   NULL | NULL


-- SELECT performed by SQL Developer
SELECT TOOL, COL1, COL1 + 1 COL1P1, DUMP(COL1, 16) DMP FROM TEST WHERE (COL1 IS NOT NULL);

 TOOL  |  COL1  | COL1P1 | DMP
---------------------------------------------------
    1  |  196   |    197 | Typ=2 Len=3: c2,2,61
    1  | NULL   |    198 | Typ=2 Len=4: c2,2,61,65
    1  | NULL   |    199 | Typ=2 Len=4: c2,2,62,65
    1  | NULL   |    200 | Typ=2 Len=4: c2,2,63,65
    1  |  200   |    201 | Typ=2 Len=2: c2,3
    2  |  196   |    197 | Typ=2 Len=3: c2,2,61
    2  |  197   |    198 | Typ=2 Len=3: c2,2,62
    2  |  198   |    199 | Typ=2 Len=3: c2,2,63
    2  |  199   |    200 | Typ=2 Len=3: c2,2,64
    2  |  200   |    201 | Typ=2 Len=2: c2,3

SELECT TOOL, COL1, COL1 + 1 COL1P1, DUMP(COL1, 16) DMP FROM TEST WHERE (COL1 IS NULL);

 TOOL  |  COL1  | COL1P1 | DMP
---------------------------------------------------
    1  |  NULL  |   NULL | NULL
    2  |  NULL  |   NULL | NULL

从测试中选择TO_NUMBER(COL1);-- ORA-01722 无效编号

这是因为 198 和 199 是触发问题的两个数字,但 196 和 200 不是。 这些是我们迄今为止(偶然)发现的数字:123、197、198、199、1480000、1490000、1700000、1710000

使用 NVL 函数还可以揭示一个事实,即这不是“真正的”NULL:

SELECT TOOL, COL1, NVL(COL1, 1000) COL1NVL, DUMP(NVL(COL1, 1000), 16) DMP FROM TEST;

 TOOL  |  COL1  | COL1NVL | DMP
---------------------------------------------------
    1  |  196   |    197 | Typ=2 Len=3: c2,2,61
    1  | NULL   |   NULL | Typ=2 Len=3: c2,2,61
    1  | NULL   |   NULL | Typ=2 Len=4: c2,2,62,65
    1  | NULL   |   NULL | Typ=2 Len=3: c2,2,64
    1  |   200  |    201 | Typ=2 Len=2: c2,3
    2  |   196  |    197 | Typ=2 Len=3: c2,2,61
    2  |   197  |    198 | Typ=2 Len=3: c2,2,62
    2  |   198  |    199 | Typ=2 Len=3: c2,2,63
    2  |   199  |    200 | Typ=2 Len=3: c2,2,64
    2  |   200  |    201 | Typ=2 Len=2: c2,3

还测试了:Oracle 客户端 19.19.0.0.0 和 21.10.0.0.0 我们的自托管数据库(相同的应用程序和 oracle 客户端)不会发生此问题。

数据库字段怎么可能处于导致这些结果的状态?

我尝试了任何可以想象的工具和客户端组合来重现一个行为如此的字段,但没有成功。 寻找新的想法或有同样问题的人。 欢迎任何建议。

SQL 数据库 Oracle Null Cloud

评论

1赞 astentx 8/9/2023
它显示了什么:?select dump(col1, 16) from your_tablw where <filter on broken rows>
1赞 Martin Schapendonk 8/9/2023
你能用 ?如果省略列表达式,结果会发生变化吗?select tool, col1 from test where col1 is nullcol + 1
1赞 astentx 8/10/2023
这回答了你的问题吗?尝试通过 PL/SQL 导出 Oracle 给出的日期为 0000-00-00
1赞 astentx 8/10/2023
应用程序使用某种方式将原始字节写入数字列。这与上述关于日期的问题相同。请参阅小提琴中的可重现示例:dbfiddle.uk/XFRN-Rem
1赞 astentx 8/10/2023
似乎当您使用算术时,Oracle 会对字节执行这些操作,然后调整其表示以确认存储规则(它将每两位数字存储为一个单独的字节)

答: 暂无答案