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

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

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

  • 0
    возможный дубликат Python - mysqlDB, sqlite результат в виде словаря
  • 1
    @ vy32: Этот вопрос относится к июлю 2010 года, а тот, с которым вы связались, - ноябрь 2010 года. Так что это обман. И, как и следовало ожидать, обратный комментарий был добавлен к этому :-)
Теги:
dictionary

11 ответов

133
Лучший ответ

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

  • 56
    Просто процитировать документы, con.row_factory = sqlite3.Row
  • 0
    Если в именах ваших столбцов есть специальные символы, например, SELECT 1 AS "dog[cat]" то cursor не будет иметь правильного описания для создания dict.
Показать ещё 3 комментария
18

Даже используя класс 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))       
  • 8
    sqlite3.Row реализует протокол сопоставления. Вы можете просто print "%(id)i - %(name)s: %(value)s" % dict(row)
15

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

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
  • 4
    В настоящее время fetchall() кажется, возвращает объекты sqlite3.Row . Однако их можно преобразовать в словарь, просто используя dict() : result = [dict(row) for row in c.fetchall()] .
8

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

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

  • 0
    > Различается между базами данных - например, sqlite 3.7 и 3.8?
  • 0
    @ user1123466: ... Как между SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird ...
3

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

db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
  • 0
    Это отлично сработало для меня. Спасибо!
2

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

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)

Вам решать :)

0

Словари в 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 (уже указано в другом ответе).

0

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

db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }
0
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)

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

0

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

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))}
0

Или вы можете преобразовать 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню