最近遇到一个达梦数据库报错“-6111: 字符串转换出错”的问题,这个问题主要是涉及到一条sql语句的执行,在此分享下这个报错的处理过程。
问题表现为:一样的表结构和数据,执行相同的SQL,在Oracle数据库中执行正常,到达梦数据库执行报错。
SQL语句大致如下:
SELECT "START_VAL", "END_VAL"
FROM
(
SELECT FLOOR(C2 / 200000) * 200000 AS START_VAL, CEIL(C2 / 200000) * 200000 - 1 AS END_VAL
FROM T1
WHERE C3 IN ('测试1', '测试2')
GROUP BY FLOOR(C2 / 200000) * 200000, CEIL(C2 / 200000) * 200000 - 1
)
WHERE START_VAL < END_VAL;

还有一个现象, 如果把最后的条件“WHERE START_VAL < END_VAL”去掉,SQL就可以正常执行,结果如下图。

客户尝试过对SQL语句中C2列使用to_number和CAST函数做显示类型转换,仍然会报错。这里不做赘述。
其实既然涉及到字符串转换出错,那问题的表象就很明显了,一定是查询语句中对应列字段真的涉及到字符串转换才会出错,数据库不会凭空报错的。
这里根据当时最终排查的结果,人工构造一批测试数据来复现下当时的情况,然后看下当时的分析过程:
--创建表
DROP TABLE IF EXISTS T1;
CREATE TABLE T1(C1 INT, C2 VARCHAR2(20), C3 VARCHAR2(50), C4 VARCHAR2(50),NOT CLUSTER PRIMARY KEY(C1));
--创建索引
CREATE INDEX IDX1 ON T1(C1 ASC,C3 ASC,C2 ASC);
--插入测试数据
DECLARE
BEGIN
FOR I IN 1..1000 LOOP
IF (I >= 1 AND I <= 200) THEN
IF MOD(I, 3) = 0 THEN
INSERT INTO T1 VALUES(I, DBMS_RANDOM.STRING('X', 10), DBMS_RANDOM.STRING('X', 10), DBMS_RANDOM.STRING('X', 10));
ELSE
INSERT INTO T1 VALUES(I, ABS(FLOOR(DBMS_RANDOM.VALUE(1000000000, 9999999999))), '测试1', DBMS_RANDOM.STRING('X', 10));
END IF;
ELSE
IF I IN (119,120,911,10086,12345,12315,12580,96577) THEN
INSERT INTO T1 VALUES(I, DBMS_RANDOM.STRING('X', 10), DBMS_RANDOM.STRING('X', 10), DBMS_RANDOM.STRING('X', 10));
ELSE
INSERT INTO T1 VALUES(I, ABS(FLOOR(DBMS_RANDOM.VALUE(1000000000, 9999999999))), '测试2', DBMS_RANDOM.STRING('X', 10));
END IF;
END IF;
END LOOP;
COMMIT;
END;
SELECT COUNT(*) FROM T1; --共计1000条数据
注意:这里的表结构中只是本次模拟表结构随意创建的C1字段主键,实际业务场景中表字段很多,C1列也并不是主键,且表T1中包含C2和C3列的索引不止一条。表实际数据有几千万条,这里只做大致的问题模拟。
出现问题的SQL语句很简单,且只涉及到一张表,查询语句只涉及到T1表的两个字段列,分别为C2、C3,在SQL中能涉及到类型转换报错的,可以大胆判断是FLOOR和CEIL函数处理数据出现的问题。FLOOR和CEIL函数的功能如下:

最低0.47元/天 解锁文章

1927

被折叠的 条评论
为什么被折叠?



