Как я могу получить dict из запроса sqlite?

python sql sqlite dictionary dataformat

85509 просмотра

13 ответа

4082 Репутация автора

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'}

или я должен сделать сам?

Автор: Meloun Источник Размещён: 21.07.2010 02:42

Ответы (13)


8 плюса

621914 Репутация автора

От 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.

Так что да, сделай это сам.

Автор: Ignacio Vazquez-Abrams Размещён: 21.07.2010 02:46

140 плюса

671093 Репутация автора

Решение

Вы можете использовать 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.Row. Row обеспечивает доступ к столбцам как на основе индексов, так и без учета регистра, почти без затрат памяти. Вероятно, это будет лучше, чем ваш собственный подход на основе словаря или даже решение на основе db_row.

Автор: Alex Martelli Размещён: 21.07.2010 02:47

19 плюса

3005 Репутация автора

Даже используя класс sqlite3.Row, вы все равно не можете использовать форматирование строк в виде:

print "%(id)i - %(name)s: %(value)s" % row

Чтобы обойти это, я использую вспомогательную функцию, которая берет строку и преобразует ее в словарь. Я использую это только тогда, когда объект словаря предпочтительнее объекта Row (например, для таких вещей, как форматирование строк, когда объект Row также не поддерживает API словаря). Но используйте объект Row все остальное время.

def dict_from_row(row):
    return dict(zip(row.keys(), row))       
Автор: bbengfort Размещён: 02.03.2012 06:19

0 плюса

678 Репутация автора

Или вы можете преобразовать sqlite3.Rows в словарь следующим образом. Это даст словарь со списком для каждой строки.

    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
Автор: andere Размещён: 21.08.2014 09:04

0 плюса

1604 Репутация автора

Общая альтернатива, использующая всего три строки

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))}
Автор: Macabeus Размещён: 13.10.2015 05:16

22 плюса

1309 Репутация автора

Я думал, что отвечу на этот вопрос, хотя ответ частично упоминается и в ответах Адама Шмидега и Алекса Мартелли. Чтобы другие, как я, задавали тот же вопрос, легко нашли ответ.

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
Автор: gandalf Размещён: 29.01.2017 11:04

3 плюса

1907 Репутация автора

Более короткая версия:

db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
Автор: M. Utku ALTINKAYA Размещён: 31.01.2017 11:41

0 плюса

182 Репутация автора

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)

Результат определенно верный, но я не знаю лучшего.

Автор: Emrah Tuncel Размещён: 27.12.2017 01:59

2 плюса

176 Репутация автора

Самый быстрый на моих тестах:

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)

против:

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)

Вам решать :)

Автор: Ran Aroussi Размещён: 14.02.2018 02:29

1 плюс

11851 Репутация автора

Подобны ранее упомянутым решениям, но наиболее компактны:

db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }
Автор: Falko Размещён: 09.04.2018 03:55

0 плюса

314 Репутация автора

Словари в python предоставляют произвольный доступ к их элементам. Таким образом, любой словарь с «именами», хотя он может быть информативным с одной стороны (иначе как называются имена полей), «отменяет порядок» полей, что может быть нежелательным.

Лучший подход - собрать имена в отдельный список, а затем объединить их с результатами самостоятельно, если это необходимо.

try:
         mycursor = self.memconn.cursor()
         mycursor.execute('''SELECT * FROM maintbl;''')
         #first get the names, because they will be lost after retrieval of rows
         names = list(map(lambda x: x[0], mycursor.description))
         manyrows = mycursor.fetchall()

         return manyrows, names

Также помните, что имена во всех подходах - это имена, которые вы указали в запросе, а не имена в базе данных. Исключением являетсяSELECT * FROM

Если ваша единственная задача - получить результаты с помощью словаря, то обязательно используйте conn.row_factory = sqlite3.Row(уже указано в другом ответе).

Автор: ilias iliadis Размещён: 24.12.2018 08:04

2 плюса

5997 Репутация автора

После подключения к SQLite: con = sqlite3.connect(.....)достаточно просто запустить:

con.row_factory = sqlite3.Row

Вуаля!

Автор: Lukasz Czerwinski Размещён: 04.05.2019 09:31

0 плюса

8151 Репутация автора

Как указано в ответе @ gandalf, нужно использовать conn.row_factory = sqlite3.Row, но результаты не являются словарями. Нужно добавить дополнительный «бросок» dictв последнем цикле:

import sqlite3
conn = sqlite3.connect(":memory:")
conn.execute('create table t (a text, b text, c text)')
conn.execute('insert into t values ("aaa", "bbb", "ccc")')
conn.execute('insert into t values ("AAA", "BBB", "CCC")')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute('select * from t')
for r in c.fetchall():
    print(dict(r))

# {'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}
# {'a': 'AAA', 'b': 'BBB', 'c': 'CCC'}
Автор: Basj Размещён: 25.10.2019 11:11
Вопросы из категории :
32x32