如何从sqlite查询中获取dict?

时间:2010-07-21 14:42:21

标签: python sql sqlite dictionary dataformat

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

或者我必须自己做?

15 个答案:

答案 0 :(得分: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类型。 Row提供两者   基于索引和不区分大小写   基于名称的列访问权限   几乎没有内存开销。它会   可能比你自己更好   基于自定义词典的方法或   甚至是基于db_row的解决方案。

答案 1 :(得分: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))       

答案 2 :(得分:18)

我想我回答了这个问题,尽管在Adam Schmideg和Alex Martelli的回答中都提到了答案。为了让像我这样有其他问题的人能够轻松找到答案。

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

答案 3 :(得分: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.

所以是的,自己动手。

答案 4 :(得分:3)

更短的版本:

db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])

答案 5 :(得分: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)

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)

你决定:)

答案 6 :(得分:1)

连接到SQLite后: con = sqlite3.connect(.....)只需运行即可:

con.row_factory = sqlite3.Row

Voila!

答案 7 :(得分:1)

获取查询结果

output_obj = con.execute(query)
results = output_obj.fetchall()

选项 1) 带 Zip 的显式循环

for row in results:
    col_names = [tup[0] for tup in output_obj.description]
    row_values = [i for i in row]
    row_as_dict = dict(zip(col_names,row_values))

选项 2) 使用 Dict Comp 加快循环

for row in results:
    row_as_dict = {output_obj.description[i][0]:row[i] for i in range(len(row))}

答案 8 :(得分: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

答案 9 :(得分:0)

通用替代方案,仅使用三行

/intl

但如果您的查询什么都不返回,则会导致错误。在这种情况下......

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

答案 10 :(得分: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)

结果绝对正确,但我不知道最好的。

答案 11 :(得分:0)

类似于之前提到的解决方案,但最紧凑:

db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }

答案 12 :(得分:0)

Python中的字典可任意访问其元素。 因此,任何带有“名称”的字典,尽管一方面可能会提供更多信息(又称字段名称),但却会使字段“无序”,这可能是不必要的。

最好的方法是将名称保存在单独的列表中,然后根据需要自己将其与结果结合起来。

Func<String, int, bool> predicate = (str, index) => str.Length == index;

还要记住,在所有方法中,名称都是您在查询中提供的名称,而不是数据库中的名称。 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(已经在另一个答案中说明了)。

答案 13 :(得分:0)

正如@gandalf的答案所提到的,必须使用conn.row_factory = sqlite3.Row,但结果不是直接的 词典。在最后一个循环中,必须向dict添加一个附加的“ cast”:

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

答案 14 :(得分:0)

我认为您在正确的轨道上。让我们保持非常简单并完成您想做的事情:

import sqlite3
db = sqlite3.connect("test.sqlite3")
cur = db.cursor()
res = cur.execute("select * from table").fetchall()
data = dict(zip([c[0] for c in cur.description], res[0]))

print(data)

缺点是.fetchall(),如果您的桌子很大,这是您消耗内存的谋杀手段。但是对于仅处理数千行文本和数字列的琐碎应用程序而言,这种简单的方法就足够了。

对于严重的问题,您应该按照其他许多答案中的建议研究行工厂。