Подтвердить что ты не робот

Извлеченный первичный ключ Обработка ошибок в Python/psycopg2

Использование Python 2.7 и

В [150]: psycopg2. версия Out [150]: '2.4.2 (dt dec pq3 ext)'

У меня есть простые сценарии python, которые обрабатывают транзакции и записывают данные в базу данных. Иногда есть вставка, которая нарушает мой первичный ключ. Это прекрасно, я просто хочу, чтобы он проигнорировал эту запись и продолжал ее веселый путь. Проблема, с которой я столкнулась, заключается в том, что ошибка первичного ключа psycopg2 прерывает весь блок транзакции и все вставки после ошибки. Вот пример ошибки

ERROR: duplicate key value violates unique constraint "encounter_id_pkey"
DETAIL:  Key (encounter_id)=(9012235) already exists.

Это следующая вставка. а не нарушение.

Inserting: 0163168~9024065
ERROR: current transaction is aborted, commands ignored until end of transaction block

Вторая ошибка повторяется для каждой вставки. Вот упрощенный цикл. Я прохожу через кадр данных pandas, но это может быть любой цикл.

conn = psycopg2.connect("dbname='XXXX' user='XXXXX' host='XXXX' password='XXXXX'")

cur = conn.cursor()

for i, val in df2.iteritems():
    try:
        cur = conn.cursor()
        cur.execute("""insert into encounter_id_table (
        encounter_id,current_date  )
        values       
        (%(create_date)s, %(encounter_id)s ) ;""",
        'encounter_id':i.split('~')[1],  
        'create_date': datetime.date.today() })           
        cur.commit()
        cur.close() 
    except Exception , e:
        print 'ERROR:', e[0]
        cur.close()
 conn.close()   

Снова основная идея состоит в том, чтобы грациозно обрабатывать Error. В изречении адмирала Нельсона Королевского флота: "Черт, маневры идут прямо на них". Или в нашем случае проклятие Ошибки идут прямо на них ". Я подумал, открыв курсор на каждой вставке, что я бы сбросил транзакционный блок. Я не хочу, чтобы reset соединение просто из-за ошибки первичного ключа Есть ли что-то, что я просто пропустил?

Спасибо за руку за ваше время.

Джон

4b9b3361

Ответ 1

Вам следует откатить транзакцию при ошибке.

Я добавил еще одну конструкцию try..except..else в приведенном ниже коде, чтобы показать точное место, где будет происходить исключение.

try:
    cur = conn.cursor()

    try:
        cur.execute("""insert into encounter_id_table (
            encounter_id,current_date  )
            values       
            (%(create_date)s, %(encounter_id)s ) ;""",
            'encounter_id':i.split('~')[1],  
            'create_date': datetime.date.today() })
    except psycopg2.IntegrityError:
        conn.rollback()
    else:
        conn.commit()

    cur.close() 
except Exception , e:
    print 'ERROR:', e[0]

Ответ 2

Прежде всего: CURRENT_DATE является зарезервированным словом в каждом стандарте SQL, а также в PostgreSQL. Вы не можете использовать его как идентификатор без двойного цитирования. Я бы настоятельно советовал не использовать его вообще. Я переименовал столбец в curdate в моем примере

Далее, я не являюсь экспертом в синтаксисе python, но вы, похоже, изменили порядок своих столбцов-столбцов:

(%(create_date)s, %(encounter_id)s )

Должно быть:

( %(encounter_id)s, %(create_date)s)

К вашему основному вопросу: вы можете вообще избежать проблемы, проверив, находится ли ключ в таблице перед его использованием в команде вставки:

INSERT INTO encounter_id_table (encounter_id, curdate)
SELECT 1234, now()::date
WHERE  NOT EXISTS (SELECT * FROM encounter_id_table t
                   WHERE t.encounter_id = 1234);

В синтаксисе Python это должно быть:

cur.execute("""INSERT INTO encounter_id_table (encounter_id, curdate)
    SELECT %(encounter_id)s, %(create_date)s,
    WHERE  NOT EXISTS (
           SELECT * FROM encounter_id_table t
           WHERE t.encounter_id = %(encounter_id)s);""",
  {'encounter_id':i.split('~')[1],  
  'create_date': datetime.date.today()})