将 CLOB 插入到从另一个数据库中选择的数据库中
inserting CLOB to database selected from another
我有两个不相关的 oracle 11g 数据库实例。我需要从一个数据库中 select 一个 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
所以我想知道这种行为是设计使然还是其他原因导致的?
这里有一些测试用的数据:
创建 table 并在数据库 1 中插入一行
create table test_table_1
(
column_1 clob
);
insert into test_table_1 (column_1) values ('test_data_1');
创建 table 并在数据库 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], [], [], [], [], [], [], [], [], []
select从数据库 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()
我有两个不相关的 oracle 11g 数据库实例。我需要从一个数据库中 select 一个 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
所以我想知道这种行为是设计使然还是其他原因导致的?
这里有一些测试用的数据:
创建 table 并在数据库 1 中插入一行
create table test_table_1
(
column_1 clob
);
insert into test_table_1 (column_1) values ('test_data_1');
创建 table 并在数据库 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], [], [], [], [], [], [], [], [], []
select从数据库 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()