Làm cách nào tôi có thể nhận được dict từ truy vấn sqlite?


118
db = sqlite.connect("test.sqlite")
res = db.execute("select * from table")

Với sự lặp lại, tôi nhận được danh sách tương ứng với các hàng.

for row in res:
    print row

Tôi có thể lấy tên của các cột

col_name_list = [tuple[0] for tuple in res.description]

Nhưng có một số chức năng hoặc cài đặt để lấy từ điển thay vì danh sách không?

{'col1': 'value', 'col2': 'value'}

hay tôi phải tự làm?



3
@ vy32: Câu hỏi này là từ tháng 7 năm 2010, câu hỏi mà bạn đã liên kết là tháng 11 năm 2010. Vậy đó là bản dupe. Và như người ta mong đợi, nhận xét ngược lại đã được đưa vào đó :-)
Aneroid

Câu trả lời:


158

Bạn có thể sử dụng row_factory , như trong ví dụ trong tài liệu:

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"]

hoặc làm theo lời khuyên được đưa ra ngay sau ví dụ này trong tài liệu:

Nếu việc trả về một tuple không đủ và bạn muốn có quyền truy cập dựa trên tên vào các cột, bạn nên cân nhắc đặt row_factory thành loại sqlite3.Row được tối ưu hóa cao. Row cung cấp cả quyền truy cập dựa trên tên dựa trên chỉ mục và không phân biệt chữ hoa chữ thường vào các cột mà hầu như không có chi phí bộ nhớ. Nó có thể sẽ tốt hơn cách tiếp cận dựa trên từ điển tùy chỉnh của riêng bạn hoặc thậm chí là giải pháp dựa trên db_row.


Nếu tên cột của bạn có các ký tự đặc biệt, ví dụ: SELECT 1 AS "dog[cat]"cột cursorsẽ không có mô tả chính xác để tạo ra một chính tả.
Crazometer

Tôi đã thiết lập connection.row_factory = sqlite3.Rowvà tôi đã thử connection.row_factory = dict_factorynhư được hiển thị nhưng cur.fetchall()vẫn cung cấp cho tôi danh sách các bộ giá trị - bất kỳ ý kiến ​​nào tại sao điều này không hoạt động?
hiển thị

@displayname, không phải tài liệu nói rằng "Nó cố gắng bắt chước một bộ giá trị trong hầu hết các tính năng của nó.". Tôi khá chắc rằng bằng cách nào đó nó giống với những gì bạn có thể nhận được collections.namedtuple. Khi tôi sử dụng, cur.fetchmany()tôi nhận được các mục như <sqlite3.Row object at 0x...>.
ony

Thậm chí 7 năm sau, câu trả lời này là bản sao và dán hữu ích nhất từ ​​các tài liệu mà tôi tìm thấy trên SO. Cảm ơn!
WillardSolutions,

40

Tôi nghĩ rằng tôi đã trả lời câu hỏi này mặc dù câu trả lời được đề cập một phần trong cả câu trả lời của Adam Schmideg và Alex Martelli. Để những người khác như tôi có cùng câu hỏi, có thể dễ dàng tìm thấy câu trả lời.

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

21
Hiện tại fetchall()dường như trả lại sqlite3.Rowđồ vật. Tuy nhiên chúng có thể được chuyển đổi sang một từ điển đơn giản bằng cách sử dụng dict(): result = [dict(row) for row in c.fetchall()].
Gonçalo Ribeiro

21

Ngay cả khi sử dụng lớp sqlite3.Row - bạn vẫn không thể sử dụng định dạng chuỗi ở dạng:

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

Để vượt qua điều này, tôi sử dụng một hàm trợ giúp lấy hàng và chuyển đổi thành từ điển. Tôi chỉ sử dụng điều này khi đối tượng từ điển thích hợp hơn đối tượng Hàng (ví dụ: đối với những thứ như định dạng chuỗi trong đó đối tượng Hàng không hỗ trợ API từ điển một cách tự nhiên). Nhưng sử dụng đối tượng Row tất cả các lần khác.

def dict_from_row(row):
    return dict(zip(row.keys(), row))       

9
sqlite3.Row thực hiện giao thức ánh xạ. Bạn chỉ có thể làmprint "%(id)i - %(name)s: %(value)s" % dict(row)
Mzzzzzz

9

Sau khi bạn kết nối với SQLite: con = sqlite3.connect(.....)chỉ cần chạy:

con.row_factory = sqlite3.Row

Thì đấy!


8

Từ 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.

Vì vậy, có, làm điều đó cho mình.


> khác nhau giữa các cơ sở dữ liệu - như cái gì, sqlite 3,7 và 3,8?
Nucular

@ user1123466: ... Giống như giữa SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird ...
Ignacio Vazquez-Abrams

3

Phiên bản ngắn hơn:

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

3

Nhanh nhất trong các bài kiểm tra của tôi:

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)

so với:

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)

Bạn quyết định :)


1

Tương tự như các giải pháp đã đề cập trước đó, nhưng nhỏ gọn nhất:

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

Điều này làm việc cho tôi, nơi mà các câu trả lời của trên db.row_factory = sqlite3.Rowkhông làm việc cho tôi (vì nó dẫn đến một JSON TypeError)
Phillip

1

Như đã đề cập trong câu trả lời của @ gandalf, người ta phải sử dụng conn.row_factory = sqlite3.Row, nhưng kết quả không trực tiếp từ điển. Người ta phải thêm một "cast" bổ sung vào dicttrong vòng lặp cuối cùng:

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

1

Tôi nghĩ rằng bạn đã đi đúng hướng. Hãy giữ điều này rất đơn giản và hoàn thành những gì bạn đang cố gắng làm:

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)

Nhược điểm của nó là .fetchall(), sẽ giết chết bộ nhớ của bạn , nếu bảng của bạn rất lớn. Nhưng đối với các ứng dụng tầm thường chỉ xử lý vài nghìn hàng văn bản và cột số, cách tiếp cận đơn giản này là đủ tốt.

Đối với những thứ nghiêm túc, bạn nên xem xét các nhà máy hàng, như được đề xuất trong nhiều câu trả lời khác.


0

Hoặc bạn có thể chuyển đổi sqlite3.Rows thành từ điển như sau. Điều này sẽ cung cấp cho một từ điển với một danh sách cho mỗi hàng.

    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

0

Một giải pháp thay thế chung, chỉ sử dụng ba dòng

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

Nhưng nếu truy vấn của bạn không trả về kết quả nào, sẽ dẫn đến lỗi. Trong trường hợp này...

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

hoặc là

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

Kết quả chắc chắn là đúng, nhưng tôi không biết rõ nhất.


0

Các từ điển trong python cung cấp quyền truy cập tùy ý vào các phần tử của chúng. Vì vậy, bất kỳ từ điển nào có "tên" mặc dù một mặt nó có thể chứa nhiều thông tin (hay còn gọi là tên trường là gì) "hủy sắp xếp" các trường, điều này có thể không mong muốn.

Cách tốt nhất là lấy tên trong một danh sách riêng và sau đó kết hợp chúng với kết quả của chính bạn, nếu cần.

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

Cũng nên nhớ rằng tên, trong tất cả các cách tiếp cận, là tên bạn đã cung cấp trong truy vấn, không phải tên trong cơ sở dữ liệu. Ngoại lệ làSELECT * FROM

Nếu mối quan tâm duy nhất của bạn là lấy kết quả bằng từ điển, thì hãy chắc chắn sử dụng conn.row_factory = sqlite3.Row(đã được nêu trong một câu trả lời khác).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.