Как я могу получить dict из запроса sqlite?
db = sqlite.connect("test.sqlite")
res = db.execute("select * from table")
С итерацией я получаю списки, соответствующие строкам.
for row in res:
print row
Я могу получить имя колонки
col_name_list = [tuple[0] for tuple in res.description]
но есть ли какая-то функция или настройка, чтобы получить словари вместо списка?
{'col1': 'value', 'col2': 'value'}
или я должен сделать сам?
10 ответов:
вы могли бы использовать row_factory, как в Примере в документации:
import sqlite3 def dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d con = sqlite3.connect(":memory:") con.row_factory = dict_factory cur = con.cursor() cur.execute("select 1 as a") print cur.fetchone()["a"]или следуйте советам, которые даны сразу после этого примера в документах:
если возврат кортежа не достаточно и вы хотите получить доступ на основе имен столбцы, вы должны рассмотреть возможность установки row_factory к высок-оптимизированному sqlite3.Тип строки. Подряд обеспечивает индекс на основе и без учета регистра доступ на основе имен к столбцам с почти без памяти. Оно будет вероятно, будет лучше, чем ваш собственный пользовательский подход на основе словаря или даже решение на основе db_row.
даже с помощью sqlite3.Класс строк-- вы все еще не можете использовать форматирование строк в виде:
print "%(id)i - %(name)s: %(value)s" % rowчтобы пройти мимо этого, я использую вспомогательную функцию, которая берет строку и преобразует ее в словарь. Я использую это только тогда, когда объект dictionary предпочтительнее объекта Row (например, для таких вещей, как форматирование строк, где объект Row не поддерживает API-интерфейс словаря). Но используйте объект строки все остальные разы.
def dict_from_row(row): return dict(zip(row.keys(), row))
Я думал, что отвечу на этот вопрос, хотя ответ частично упоминается в ответах Адама Шмидега и Алекса Мартелли. Для того, чтобы другие, как я, которые имеют тот же вопрос, чтобы найти ответ легко.
conn = sqlite3.connect(":memory:") #This is the important part, here we are setting row_factory property of #connection object to sqlite3.Row(sqlite3.Row is an implementation of #row_factory) conn.row_factory = sqlite3.Row c = conn.cursor() c.execute('select * from stocks') result = c.fetchall() #returns a list of dictionaries, each item in list(each dictionary) #represents a row of the table
С PEP 249:
Question: How can I construct a dictionary out of the tuples returned by .fetch*(): Answer: There are several existing tools available which provide helpers for this task. Most of them use the approach of using the column names defined in the cursor attribute .description as basis for the keys in the row dictionary. Note that the reason for not extending the DB API specification to also support dictionary return values for the .fetch*() methods is that this approach has several drawbacks: * Some databases don't support case-sensitive column names or auto-convert them to all lowercase or all uppercase characters. * Columns in the result set which are generated by the query (e.g. using SQL functions) don't map to table column names and databases usually generate names for these columns in a very database specific way. As a result, accessing the columns through dictionary keys varies between databases and makes writing portable code impossible.Так что да, сделайте это сами.
более короткая версия:
db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
самый быстрый на моих тестах:
conn.row_factory = lambda c, r: dict(zip([col[0] for col in c.description], r)) c = conn.cursor() %timeit c.execute('SELECT * FROM table').fetchall() 19.8 µs ± 1.05 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)vs:
conn.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)]) c = conn.cursor() %timeit c.execute('SELECT * FROM table').fetchall() 19.4 µs ± 75.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)вы определитесь :)
или вы можете конвертировать sqlite3.Строки в словарь следующим образом. Это даст словарь со списком для каждой строки.
def from_sqlite_Row_to_dict(list_with_rows): ''' Turn a list with sqlite3.Row objects into a dictionary''' d ={} # the dictionary to be filled with the row data and to be returned for i, row in enumerate(list_with_rows): # iterate throw the sqlite3.Row objects l = [] # for each Row use a separate list for col in range(0, len(row)): # copy over the row date (ie. column data) to a list l.append(row[col]) d[i] = l # add the list to the dictionary return d
общая альтернатива, используя только три строки
def select_column_and_value(db, sql, parameters=()): execute = db.execute(sql, parameters) fetch = execute.fetchone() return {k[0]: v for k, v in list(zip(execute.description, fetch))} con = sqlite3.connect('/mydatabase.db') c = con.cursor() print(select_column_and_value(c, 'SELECT * FROM things WHERE id=?', (id,)))а если запрос ничего не возвращает, приведет к ошибке. В этом деле...
def select_column_and_value(self, sql, parameters=()): execute = self.execute(sql, parameters) fetch = execute.fetchone() if fetch is None: return {k[0]: None for k in execute.description} return {k[0]: v for k, v in list(zip(execute.description, fetch))}или
def select_column_and_value(self, sql, parameters=()): execute = self.execute(sql, parameters) fetch = execute.fetchone() if fetch is None: return {} return {k[0]: v for k, v in list(zip(execute.description, fetch))}
import sqlite3 db = sqlite3.connect('mydatabase.db') cursor = db.execute('SELECT * FROM students ORDER BY CREATE_AT') studentList = cursor.fetchall() columnNames = list(map(lambda x: x[0], cursor.description)) #students table column names list studentsAssoc = {} #Assoc format is dictionary similarly #THIS IS ASSOC PROCESS for lineNumber, student in enumerate(studentList): studentsAssoc[lineNumber] = {} for columnNumber, value in enumerate(student): studentsAssoc[lineNumber][columnNames[columnNumber]] = value print(studentsAssoc)результат определенно верен, но я не знаю лучшего.
похожие, как и ранее упомянутые решения, но наиболее компактные:
db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }
Comments