提问人:Henning 提问时间:8/9/2023 最后编辑:Henning 更新时间:9/19/2023 访问量:60
在 Oracle 云数据库中假装为 NULL 的 NUMBERS
NUMBERS pretending to be NULL in Oracle Cloud Database
问:
我们的 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 客户端)不会发生此问题。
数据库字段怎么可能处于导致这些结果的状态?
我尝试了任何可以想象的工具和客户端组合来重现一个行为如此的字段,但没有成功。 寻找新的想法或有同样问题的人。 欢迎任何建议。
答: 暂无答案
评论
select dump(col1, 16) from your_tablw where <filter on broken rows>
select tool, col1 from test where col1 is null
col + 1