python - 将 CLOB 插入从另一个数据库中选择的数据库

标签 python oracle cx-oracle

我有两个不相关的 Oracle 11g 数据库实例。我需要从一个数据库中选择一个 CLOB 类型的值,然后使用 cx_Oracle 通过 python 将其插入到另一个数据库中。

当我朝一个方向尝试时,结果是:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist

奇怪的是,当朝另一个方向尝试时,结果是:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: internal error code, arguments: [kglslod:subheap], [8], [0x14D9EA270], [], [], [], [], [], [], [], [], []

在同一数据库中选择和插入 CLOB 值没有问题。

我发现我可以使用自定义输出处理程序修复它:

def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
    if defaultType == cx_Oracle.CLOB:
        return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)

和设置

db_connection.outputtypehandler = OutputTypeHandler

所以我想知道这种行为是设计使然还是还有其他原因导致这种情况?


这里有一些测试数据:

创建表并在数据库1中插入一行

create table test_table_1
(
    column_1 clob
);

insert into test_table_1 (column_1) values ('test_data_1');

创建表并在数据库2中插入一行

create table test_table_2
(
    column_2 clob
);

insert into test_table_2 (column_2) values ('test_data_2');

Python 脚本无法从数据库 1 获取一个结果并将其插入数据库 2

import cx_Oracle


db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()

cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])

结果

Traceback (most recent call last):
  File "<input>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-00600: Interner Fehlercode, Argumente: [kglslod:subheap], [8], [0x14DF5A0B0], [], [], [], [], [], [], [], [], []

从数据库2中选择并插入数据库1时的结果

Traceback (most recent call last):
  File "<input>", line 8, in <module>
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist

有效的Python脚本

import cx_Oracle

def OutputTypeHandler(cursor: cx_Oracle.Cursor, name, defaultType, size, precision, scale):
    """
    Convertes CLOB type to string on reading.
    """
    if defaultType == cx_Oracle.CLOB:
        return cursor.var(cx_Oracle.LONG_STRING, arraysize=cursor.arraysize)

db_1 = cx_Oracle.connect(<user>, <passwd>, <host_db1>)
db_1.outputtypehandler = OutputTypeHandler
db_2 = cx_Oracle.connect(<user>, <passwd>, <host_db2>)

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

result = cursor_1.execute("select column_1 from test_table_1")
result1 = result.fetchone()

cursor_2.execute("insert into test_table_2(column_2) values (:val)", val=result1[0])

db_2.commit()

版本

  • cx-Oracle 7.2.0
  • oracle_instant_client 18.5(Linux)
  • python 3.6.8

最佳答案

您不能简单地将 LOB 值从一个连接传递到另一个连接。它们特定于特定连接。我会考虑针对这种情况提供更好的错误消息

正如您在自己的问题中指出的,第一个解决方案是通过使用输出类型处理程序来使用 STRING 而不是 CLOB。该技术适用于最大 1 GB 的 CLOB 值,但缺点是整个 CLOB 值必须驻留在连续的内存中。

如果由于长度太长而需要流式传输值,则需要使用类似以下的内容:

cursor_1 = db_1.cursor()
cursor_2 = db_2.cursor()

cursor_1.execute("select column_1 from test_table_1")
sourceLob, = cursor_1.fetchone()

lobVar = cursor_2.var(cx_Oracle.CLOB)
cursor_2.execute("insert into test_table_2 (column_2) values (empty_clob()) returning column_2 into :1", [lobVar])
destLob = lobVar.getvalue()

offset = 1
numBytesInChunk = 65536
while True:
    data = sourceLob.read(offset, numBytesInChunk)
    if data:
        destLob.write(data, offset)
    if len(data) < numBytesInChunk:
        break
    offset += len(data)
db_2.commit()

关于python - 将 CLOB 插入从另一个数据库中选择的数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57177429/

相关文章:

python - 对pytorch中的数据集应用转换并将其添加到数据中

使用带代理的 SSL 证书的 Python 错误

oracle - 使用 Oracle 删除 LF

python - py2exe/cx_Oracle - 生成的 dist 中的 OCI.dll

python - 无法解开从 pandas DataFrame 继承的类

sql - 在 blob 上选择不同的

oracle - 比较和对比变更数据捕获和数据库变更通知

python - 允许关闭数据库时关闭 cx_Oracle 连接

python - 将变量传递给 SQL 查询 Python 时出错

python - 将变量传递给 Django 2 中的 href 模板