2013-06-18 18 views
11

Próbuję wstawić dane ze słownika do bazy danych przy użyciu nazwanych parametrów. Mam to działa z prostą instrukcją SQL, np.python sqlite insert o nazwie parametry lub null

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

Wstawia gdzieś do lokalizacji, 1000 w kolumnie Przybycie i 1001 w kolumnie odlotu.

Dane, które faktycznie będę zawierał będą zawierać lokalizację, ale mogą zawierać zarówno przybycie, jak i odlot, ale mogą nie mieć obu (w takim przypadku nic lub NULL nie może przejść do tabeli). W tym przypadku, mam sqlite3.ProgrammingError: Nie dostarczyć wartość dla wiązania 2.

mogę rozwiązać ten problem za pomocą defaultdict:

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

do rzeczy nieco bardziej skomplikowana, będę rzeczywiście lista słowników zawierających wiele lokalizacji wraz z przybyciem lub odlotem.

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

i chcę, aby być w stanie uruchomić ten z c.executemany jednak teraz nie można używać defaultdict.

Potrafię przeglądać każdy słownik na liście i uruchamiać wiele instrukcji c.execute, ale executemany wydaje się być bardziej przejrzystą metodą.

Uproszyłem ten przykład dla wygody, rzeczywiste dane zawierają dużo więcej wpisów w słowniku i buduję je z pliku tekstowego JSON.

Ktoś ma jakieś sugestie, jak mógłbym to zrobić?

Odpowiedz

12

Zastosowanie None aby wstawić NULL:

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

Można użyć domyślny słownik i generator używać tego z 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) 
+0

Thanks Martin - który działa. Dla każdego, kto ma ten problem, domyślny słownik musi zawierać wpis do każdego możliwego elementu, nawet jeśli rzeczywisty słownik zawsze będzie go zawierał. Brak również końcowego nawiasu zamykającego w linii executemany. – user2497185

0

Jest prostsze rozwiązanie tego problemu, który powinien być wykonalne w większości przypadków; prostu przejść doexecutemanylistędefaultdictzamiast wykazudict.

Innymi słowy, jeśli zbudować od podstaw swoje wiersze jako defaultdict można przekazać listę defaultdict wierszy bezpośrednio do komendy executemany, zamiast budować je w słownikach, a potem patch sytuacji przed użyciem executemany.

Poniższy przykład roboczego (Python 3.4.3) pokazuje punkt:

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() 

Jeśli go uruchomić, to drukuje:

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