ORA-01461:仅可以为插入 LONG 列的 LONG 值赋值

背景

在一个Flask + Oracle项目中,使用第三方库cx_oracle在更新表时突然出现了报错:

1
cx_Oracle.DatabaseError: ORA-01461: 仅可以为插入 LONG 列的 LONG 值赋值

表结构如下:

1
2
3
4
5
6
7
8
9
10
-- Create table
create table FW_SRC_POOLS
(
id NUMBER not null,
isvaild VARCHAR2(1) default 1 not null,
name VARCHAR2(1000) not null,
department VARCHAR2(1000) not null,
ip VARCHAR2(4000) not null,
description VARCHAR2(4000)
)

排查过程

先根据错误号,看下说明,可能原因有如下三种。

1、插入到字符串长度大于4000字节。
2、插入到表中的记录的某个字段数据的实际长度大于2000个字节(如果是UTF-8,则是1333个字节);或者是插入的记录中有两个或两个以上长度大于2000字节的字符串。
3、数据库与客户端的JDBC驱动不匹配。

  • 检查字符串长度

    考虑可能是ip字段过长,打印一下长度:

    1
    2
    len(s)
    3653

    虽然比较长,但是还是在表字段定义的长度4000范围之内的。

    尝试直接连接数据库操作:

    1
    update FW_SRC_POOLS set ip = 'xxxx' where id = 'XXX'

    发现也是执行成功的。

  • 检查字符串编码类型

    unicode

    的确是unicode类型,那么我们通过str()转换成str类型试下,果然就成功了。

结论

不同类型的字符编码在oracle中占据的长度是不同的,在python2环境下,使用str类型要比unicode类型节省空间,但python3中默认都是unicode,应该就比较麻烦一点。不过这也仅仅是比较偷懒的做法。

再看下oracle官网的说明,还是建议把字段类型换成CLOB,可以一劳永逸。

The Oracle docs note this on the ORA-01461 error:

  • ORA-01461 can bind a LONG value only for insert into a LONG column

    Cause: An attempt was made to insert a value from a LONG datatype into another datatype. This is not allowed.

Action: Do not try to insert LONG datatypes into other types of columns.

Answer: The LONG and LONG RAW datatypes have been deprecated and the easiest solution to the ORA-01461 error is to change the column datatype to as CLOB.

http://www.dba-oracle.com/t_ora_01461_can_bind_a_long_value_only_for_insert_into_a_long_column.htm