Reputation: 69
I'm new to using sqlite and I'm trying to write a class in Python which will handle all logging for a program that I'm writing.
The class receives a dictionary whose keys are the names of the columns of the database and values are the entries for that row. Now the dictionary may not have entries for all columns so I want to just log those entries that exist and set some default value if no entry can be found for these columns. The function I have at the moment in my class is something like this:
def AddRow(self, Row, Header):
keys = ''
values = ''
for key in Header:
if keys and values:
keys += ','
values += ','
try:
keys += string(key)
values += string(Row[key])
except:
keys += string(key)
values += '0.0'
print keys
print values
self.c.execute("INSERT INTO {tn} ({k}) VALUES ({v})".format(tn=self.Table_Name, k=keys, v=values))
Firstly it doesn't compile with the error "sqlite3.OperationalError: near ")": syntax error"
secondly the way Im approaching this seems very clumsy is there a better/easier way then to populate a string first before executing?
Upvotes: 2
Views: 73
Reputation: 1124858
Do not generate the SQL from values. Use SQL parameters instead:
def AddRow(self, Row, Header):
columns = ', '.join(Header)
params = ', '.join([':{}'.format(k) for k in Header])
sql = "INSERT INTO {} ({}) VALUES ({})".format(self.Table_Name, columns, params)
Row = dict(dict.fromkeys(Header, 0.0), **Row)
self.c.execute(sql, Row)
The sqlit3
adapter supports two styles of SQL parameters; positional (?
) and named (:name
); using named parameters lets you use a dictionary as the parameter source.
The above method generates the column names and named parameters for each of the columns, then makes sure that there are values for all columns by generating a new dictionary with all keys set to 0.0
, then overriding any keys with those found in Row
.
By using named parameters you get several benefits:
A quick demo session to illustrate what the above produces:
>>> Row = {'foo': 42, 'bar': 81}
>>> Header = ['foo', 'bar', 'baz']
>>> columns = ', '.join(Header)
>>> params = ', '.join([':{}'.format(k) for k in Header])
>>> "INSERT INTO {} ({}) VALUES ({})".format('demo_tablename', columns, params)
'INSERT INTO demo_tablename (foo, bar, baz) VALUES (:foo, :bar, :baz)'
>>> dict(dict.fromkeys(Header, 0.0), **Row)
{'bar': 81, 'foo': 42, 'baz': 0.0}
Upvotes: 2