cx_Oracle выполнит много с CLOB - PullRequest
2 голосов
/ 08 июля 2011

Я пытаюсь проанализировать несколько CSV и вставить их данные в таблицы с помощью cx_Oracle. У меня нет проблем с вставкой в ​​таблицы с использованием execute, но когда я пытаюсь выполнить ту же процедуру с executemany, я получаю сообщение об ошибке. Мой код с использованием execute, который работает

with open(key,'r') as file:
    for line in file:
        data = data.split(",")
        query = "INSERT INTO " + tables[key] + " VALUES ("
        for col in range(len(data)):
            query += ":" + str(col) + ","
        query = query[:-1] + ")"            
        cursor.execute(query, data)

но когда я заменяю его на

with open(key,'r') as file:
    list = []
    for line in file:
        data = data.split(",")
        list.append(data)
    if len(list) > 0:
        query = "INSERT INTO " + tables[key] + " VALUES ("
        for col in range(len(data)):
            query += ":" + str(col) + ","
        query = query[:-1] + ")"            
        cursor.prepare(query)
        cursor.executemany(None,list)

Я получаю «ValueError: слишком большие строковые данные» при попытке вставить в таблицу, в которой есть столбцы CLOB и размер данных превышает 4000 байтов. Executemany прекрасно работает, когда в таблице нет столбца CLOB. Есть ли способ, которым я могу сказать cx_Oracle обрабатывать соответствующие столбцы как CLOB, когда он выполняется во многих случаях?

1 Ответ

4 голосов
/ 28 августа 2012

Попробуйте установить размер ввода для больших столбцов на cx_Oracle.CLOB. Может не работать, если у вас есть двоичные данные, но должно работать с любым текстом, который у вас есть в CSV. Значение 2K, вероятно, ниже, чем должно быть.

Обратите внимание, что executemany выглядит намного медленнее, когда задействовано CLOB столбцов, но все же лучше, чем повторное выполнение:

def _executemany(cursor, sql, data):
    '''
    run the parameterized sql with the given dataset using cursor.executemany 
    if any column contains string values longer than 2k, use CLOBS to avoid "string
    too large" errors.

    @param sql parameterized sql, with parameters named according to the field names in data
    @param data array of dicts, one per row to execute.  each dict must have fields corresponding
                to the parameter names in sql
    '''
    input_sizes = {}
    for row in data:
        for k, v in row.items():
            if isinstance(v, basestring) and len(v) > 2000:
                input_sizes[k] = cx_Oracle.CLOB
    cursor.setinputsizes(**input_sizes)
    cursor.executemany(sql, data)
...