Копирование в Postgres в цикле while - PullRequest
0 голосов
/ 23 января 2019

Имея несколько странную проблему с python, не уверен, что это как-то связано с psycopg2 или какой-то ошибкой новичка, которую я делаю с python.

По сути, у меня есть функция, которая копирует данные из csv и пытаетсявставьте его в базу данных pgsql с помощью psycopg2.Если есть ошибка типа данных, я хочу, чтобы код попытался исправить ее, а затем снова попытаться вставить данные в базу данных.вот код:

def copy(self, csvFile):
    error = True
    i = 0
    while error:
        try:
            i += 1
            print(f'attempt {i}')
            self.connect()
            csr = self.conn.cursor()
            csr.copy_expert("COPY foo.bar FROM STDOUT NULL '' CSV HEADER", csvFile)
        except psycopg2.DataError as err:
            print(err)
            print(err.pgcode)
            csr.close()
            self.conn.close()
            #self.conn.rollback()
            if err.pgcode == '22001':
                if 'character varying' in err.args[0]:
                    currlength = re.search(r'\((.*?)\)', err.args[0]).group(1)
                    newlength = int(currlength) * 2
                    s = err.args[0].split()
                    col = s[s.index('column') + 1].replace(':','')
                    sql = f'alter table foo.bar alter column {col} type varchar({newlength})'
                    print(f'Column Length too short adjusting {col} from {currlength} to {newlength}\n {sql}')
                    self.execute(sql)
            elif err.pgcode == '22p02':
                s = err.args[0].split()
                col = s[s.index('column') + 1].replace(':', '')
                sql = f'alter table foo.bar alter column {col} varchar(64)'
                print(f'numeric column {col} contains text altering to varchar')
                self.execute(sql)
        else:
            self.conn.commit()
            csr.close()
            error = False

В результате получается, что первая попытка выполняется так, как ожидается, и выдает ошибку, затем оператор alter table выполняется правильно, со второй попытки функция copy_expert ничего не делает, но не выдает ошибку икод завершается без вставки данных CSV в базу данных.Это вывод, показывающий, что он пытается во второй раз.

> attempt 1 
> value too long for type character varying(1) CONTEXT:  COPY
table, line 3, column id: "12345678"
> 
> 22001 
> Column Length too short adjusting assetid from 1 to 2  
> alter table foo.bar alter column id type varchar(2) 
> Executing query alter table foo.bar alter column assetid type varchar(2)             
> attempt 2
> Download and insert of file.csv Complete

1 Ответ

0 голосов
/ 25 января 2019

Итак, потратив ~ 30 минут с энтузиазмом, идя по тупику, я думаю, что нашел причину проблемы. Это не имеет ничего общего с psycopg2, и я не буду называть это ошибкой новичка. Я был совершенно уверен, что речь идет об уровнях изоляции ... это не так.

Это дескриптор файла. Файл полностью прочитан copy_expert, поэтому внутренний указатель находится в конце, когда повышается psycopg2.DataError. Во второй раз просто нечего читать с этой ручки.

Если вы поместите csvFile.seek(0) в свой блок except, указатель будет сброшен на начало файла.

except psycopg2.DataError as err:
    csvFile.seek(0)

Я создал небольшой тестовый класс с использованием вашего метода copy и реализовал методы execute и connect так, как я и предполагал.
Мне удалось воспроизвести поведение, которое вы описали в своем посте, и сброс указателя в блоке except привел к тому, что данные в файле были видны в базе данных после второй попытки, после изменения длины столбца.

...