python sqlite вставить именованные параметры или ноль

Я пытаюсь вставить данные из словаря в базу данных, используя именованные параметры. У меня это работает с простым оператором SQL, например.

SQL = "INSERT INTO status (location, arrival, departure) VALUES (:location, :arrival,:departure)"
dict = {'location': 'somewhere', 'arrival': '1000', 'departure': '1001'}
c.execute(SQL,dict)

Вставляется куда-нибудь в местоположение, 1000 в столбец прибытия и 1001 в столбец отправления.

Данные, которые у меня будут на самом деле, будут содержать местоположение, но могут содержать либо прибытие, либо отправление, но могут не иметь обоих (в этом случае в таблицу может попасть либо ничего, либо NULL). В этом случае я получаю sqlite3.ProgrammingError: вы не указали значение для привязки 2.

Я могу исправить это, используя defaultdict:

c.execute(SQL,defaultdict(str,dict))

Чтобы немного усложнить ситуацию, у меня будет список словарей, содержащих несколько мест с прибытием или отправлением.

    ({'location': 'place1', 'departure': '1000'},
    {'location': 'palce2', 'arrival': '1010'},
    {'location': 'place2', 'departure': '1001'})

и я хочу иметь возможность запускать это с помощью c.executemany, однако теперь я не могу использовать defaultdict.

Я мог бы пройтись по каждому словарю в списке и запустить множество операторов c.execute, но executemany кажется более аккуратным способом сделать это.

Я упростил этот пример для удобства, фактические данные имеют гораздо больше записей в словаре, и я создаю их из текстового файла JSON.

У кого-нибудь есть предложения, как я могу это сделать?


person user2497185    schedule 18.06.2013    source источник


Ответы (2)


Используйте None, чтобы вставить NULL:

dict = {'location': 'somewhere', 'arrival': '1000', 'departure': None}

Вы можете использовать словарь по умолчанию и генератор, чтобы использовать это с executemany():

defaults = {'location': '', 'arrival': None, 'departure': None}

c.executemany(SQL, ({k: d.get(k, defaults[k]) for k in defaults} for d in your_list_of_dictionaries)
person Martijn Pieters    schedule 18.06.2013
comment
Спасибо, Мартин, это работает. Для всех, кто столкнулся с этой проблемой, словарь по умолчанию должен содержать запись для каждого возможного элемента, даже если он всегда будет в реальном словаре. Кроме того, в строке executemany отсутствует закрывающая скобка. - person user2497185; 18.06.2013

У этой проблемы есть более простое решение, которое должно быть осуществимо в большинстве случаев; просто перейдите к executemany списку defaultdict вместо списка dict.

Другими словами, если вы создаете с нуля свои строки как defaultdict, вы можете передать список defaultdict строк непосредственно команде executemany вместо того, чтобы создавать их как словари и позже исправлять ситуацию перед использованием executemany.

Следующий рабочий пример (Python 3.4.3) показывает суть:

import sqlite3
from collections import defaultdict
# initialization
db = sqlite3.connect(':memory:')
c = db.cursor()
c.execute("CREATE TABLE status(location TEXT, arrival TEXT, departure TEXT)")
SQL = "INSERT INTO status VALUES (:location, :arrival, :departure)"
# build each row as a defaultdict
f = lambda:None # use str if you prefer
row1 = defaultdict(f,{'location':'place1', 'departure':'1000'})
row2 = defaultdict(f,{'location':'place2', 'arrival':'1010'})
rows = (row1, row2)
# insert rows, executemany can be safely used without additional code
c.executemany(SQL, rows)
db.commit()
# print result
c.execute("SELECT * FROM status")
print(list(zip(*c.description))[0])
for r in c.fetchall():
    print(r)
db.close()

Если вы запустите его, он напечатает:

('location', 'arrival', 'departure')
('place1', None, '1000') # None in Python maps to NULL in sqlite3
('place2', '1010', None)
person mmj    schedule 21.08.2015