为什么在相同 type/width 的列之间复制数据时会出现 'ORA-12899: value too large for column' 错误?

Why do I get 'ORA-12899: value too large for column' error when copying data between columns of the same type/width?

我有一个 java 小程序,可以将数据从一个数据库复制到另一个数据库。两个数据库都有相同的列,副本是使用 sql 开发人员的“复制数据库”选项创建的,以创建所有对象。这两个数据库都是 oracle 12.2.0 企业版,但目标位于 docker 映像中,将用于开发。仅复制一个 table:

时出现奇怪的错误

ORA-12899: 列“MY_SCHEMA”的值太大。“MY_TABLE”。“MY_COLUMN”(实际:101,最大值:100)

两个数据库在此列上的宽度相同,所以不确定为什么会抱怨。两者都是 VARCHAR2(100)。也许是我的 java 代码有问题?本质上是这样做的:

  List<Column> cols = getCols("MY_SCHEMA", "MY_TABLE",sourceConn.getMetaData());
  String sourceTableQuery = ...; //select * from my_table
  String destinationTableInsertQuery = ...;//insert into my_table(...) values(...)
  PreparedStatement queryStmt = sourceConn.prepareStatement(sourceTableQuery); 
  ResultSet data = queryStmt.executeQuery();
  PreparedStatement insertStmt = destionationConn.prepareStatement(destinationTableInsertQuery); 

  while (data.next()) {
      for(int i = 0; i < cols.size(); i++) {
         insertStmt.setObject(i+1, data.getObject(cols.get(i).getName())); 
      }
      insertStmt.addBatch();

  }
  int [] results = insertStmt.executeBatch();

编辑:两列的确切数据类型都是 VARCHAR2(100 BYTE)。抱歉,如果造成任何混淆。

默认情况下,如果您将列声明为 varchar2(100),您将分配 100 字节的存储空间。根据数据和数据库字符集,1 个字符可能占用 1 个字节的存储空间、2 个字节、3 个字节或 4 个字节。因此 varchar2(100) 列可以存储 25 到 100 个字符,具体取决于数据和数据库字符集。

我敢打赌这两个数据库的数据库字符集(nls_characterset in v$nls_parameters)是不同的。我的猜测是目标数据库使用可变长度的 UTF-8 字符集,而源数据库使用固定宽度的字符集。在失败的行中,至少有一个字符在 UTF-8 字符集中需要 2 个字节的存储,而在源数据库的字符集中只需要 1 个字节的存储。 (请注意,UTF-8 字符集支持的字符范围比源数据库的字符集。)

您可以在两个数据库中或至少在目标数据库中将列声明为 varchar2(100 CHAR)(使用字符长度语义而不是字节长度语义)。这将为 100 个字符分配 space,而不管数据需要多少字节(请注意,varchar2 列的长度限制仍然以字节表示,因此这不适用于 varchar2(4000) 列,除非您启用了扩展字符串大小)。

如果您将所有 DDL 放在一个地方并且该 DDL 未指定字符或字节语义,您可以执行

alter session set nls_length_semantics = CHAR

在 运行 DDL 之前,如果您不想通过和编辑 DDL,则可以在源数据库中创建您的对象。

更新数据库字符集的步骤。请不要在没有阅读的情况下执行此操作,因为它可能会损坏您的数据库。我不得不使用 INTERNAL_USE 关键字,因为 WE8MSWIN1252 不是 AL32UTF8 的超集。我不在乎,因为我可以在我的本地数据库中重新加载任何损坏的数据。

立即关机

启动限制

改变数据库字符集INTERNAL_USE WE8MSWIN1252;

立即关机

启动