ORACLE PL/SQL中字符串比较异常及长度多1问题求助
问题描述
在Oracle PL/SQL中读取Excel导出的CSV文件并提取列值时,遇到字符串比较不符合预期的问题:
- 变量
v_value5显示的值正常,但IF条件无法匹配 - 调用
LENGTH(TRIM(v_value5))时,结果总是比实际长度多1,比如v_value5看起来是'E',但长度返回2
相关调试代码及输出:
DBMS_OUTPUT.PUT_LINE('Length -> '|| LENGTH(TRIM(v_value5))); -- 输出结果:2
完整处理逻辑代码:
v_file := UTL_FILE.FOPEN('TEST', 'Test.csv', 'R',30000); LOOP BEGIN UTL_FILE.GET_LINE(v_file, v_line); v_value1 := REGEXP_SUBSTR(v_line, '[^,]+', 1, 1); v_value2 := REGEXP_SUBSTR(v_line, ',.+', 1, 1); v_value3 := REPLACE(v_value2, ',', ''); v_value4 := REPLACE(v_value3, ' ', ''); v_value5 := REPLACE(v_value4, '"', ''); IF LENGTH(v_value5) > 1 THEN IF v_value5 = 'E' THEN v_Id := '1'; ELSIF v_value5 = 'D' THEN v_Id := '2'; ELSIF v_value5 = 'E' THEN v_Id := '3'; ELSIF v_value5 = 'DS' THEN v_Id := '4'; ELSIF v_value5 = 'EDS' THEN v_Id := '5'; ELSE DBMS_OUTPUT.PUT_LINE('No such Data found'); END IF; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN EXIT; END; END LOOP; UTL_FILE.FCLOSE(v_file);
注:v_value5的类型为VARCHAR(255)
问题原因及解决方案
核心原因
Excel导出的CSV文件大概率包含不可见的回车符CHR(13):Windows系统下文本文件采用CR+LF(即CHR(13)+CHR(10))作为换行标识,而UTL_FILE.GET_LINE仅会截断CHR(10),将CHR(13)保留在字符串末尾,导致长度多1,此时v_value5实际是'E'||CHR(13),自然无法和纯'E'匹配。
此外代码还存在两个额外问题:
- 正则
REGEXP_SUBSTR(v_line, ',.+', 1, 1)会从第一个逗号取到行尾,若后续字段带引号且包含逗号,会导致数据提取错误 - IF条件中重复了
v_value5 = 'E'的判断,第二个分支永远不会被触发
解决方案
1. 清除隐藏控制字符
在处理v_value5时,增加对回车符的过滤:
v_value5 := REPLACE(REPLACE(v_value4, '"', ''), CHR(13), '');
或者用正则批量清除所有非打印控制字符:
v_value5 := REGEXP_REPLACE(v_value4, '[[:cntrl:]]', ''); v_value5 := REPLACE(v_value5, '"', '');
2. 修正CSV字段提取逻辑
改用兼容带引号字段的正则提取第2个字段:
-- 提取第2个字段,支持带引号且包含逗号的场景 v_value2 := REGEXP_SUBSTR(v_line, '(".*?"|[^",]+)', 1, 2, 'i'); -- 去掉字段两端的引号 v_value2 := REPLACE(v_value2, '"', '');
3. 修复重复的IF分支
删除重复的判断,调整为合理的分支顺序:
IF v_value5 = 'E' THEN v_Id := '1'; ELSIF v_value5 = 'D' THEN v_Id := '2'; ELSIF v_value5 = 'DS' THEN v_Id := '4'; ELSIF v_value5 = 'EDS' THEN v_Id := '5'; ELSE DBMS_OUTPUT.PUT_LINE('No such Data found'); END IF;
4. 调试辅助技巧
用DUMP函数查看字符串的实际字节内容,确认是否存在隐藏字符:
DBMS_OUTPUT.PUT_LINE(DUMP(v_value5));
例如'E'||CHR(13)的DUMP结果会明确显示包含ASCII码为13的字符。
内容的提问来源于stack exchange,提问作者Seegel
相关产品推荐
相关产品推荐

