2010-07-21 10 views
71
db = sqlite.connect("test.sqlite") 
res = db.execute("select * from table") 

Con la iteración consigo listas que corresponden a las filas.¿Cómo puedo obtener el dict de la consulta sqlite?

for row in res: 
    print row 

puedo obtener el nombre de las columnas

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

pero ¿hay alguna función o la configuración para obtener los diccionarios en lugar de la lista?

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

o tengo que hacer yo solo?

+0

posible duplicado de [Python - MySQLdb, resultado de SQLite como diccionario] (http: // stackoverflow.com/questions/4147707/python-mysqldb-sqlite-result-as-dictionary) – vy32

+1

@ vy32: Esta pregunta es de julio de 2010, la que vinculaste es en noviembre de 2010. Así que esa es la tonta. Y como era de esperar, el comentario inverso se ha puesto en ese :-) – aneroid

Respuesta

109

Usted podría utilizar row_factory, como en el ejemplo, en los documentos:

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

o seguir el consejo que se da justo después de este ejemplo en los documentos:

Si devolviendo una tupla doesn' t es suficiente y desea tener acceso basado en nombres a las columnas , debe considerar establecer row_factory en el tipo altamente optimizado sqlite3.Row. Row proporciona basado en índice y no distingue entre mayúsculas y minúsculas acceso basado en nombre a las columnas con casi sin gastos generales de memoria. Será probablemente sea mejor que su propio enfoque basado en el diccionario personalizado o incluso una solución basada en db_row.

+49

Solo para citar los documentos, 'con.row_factory = sqlite3.Row' –

+0

Si los nombres de sus columnas tienen caracteres especiales en por ejemplo, 'SELECT 1 AS" dog [cat] "' ​​luego el 'cursor' no tendrá la descripción correcta para crear un dict. – Crazometer

+0

He establecido 'connection.row_factory = sqlite3.Row' y probé' connection.row_factory = dict_factory' como se muestra, pero 'cur.fetchall()' aún me da una lista de tuplas - alguna idea de por qué esto no funciona ? – displayname

6

De 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. 

Así que sí, hágalo usted mismo.

+0

> varía entre bases de datos - como qué, sqlite 3.7 y 3.8? – Nucular

+0

@ user1123466: ... Al igual que entre SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird ... –

15

Incluso utilizando el sqlite3.Row class-- todavía no se puede utilizar el formato de cadenas en forma de:

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

Con el fin de conseguir más allá de esto, yo utilizo una función auxiliar que lleva el remar y convertir a un diccionario. Solo uso esto cuando el objeto del diccionario es preferible al objeto Fila (por ejemplo, para cosas como el formato de cadenas donde el objeto Row no admite de forma nativa la API del diccionario también). Pero use el objeto Fila todas las demás veces.

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

sqlite3.Row implementa el protocolo de mapeo. Simplemente puede hacer 'print"% (id) i -% (name) s:% (value) s "% dict (row)' – Mzzzzzz

0

O podría convertir el sqlite3.Rows en un diccionario de la siguiente manera. Esto dará un diccionario con una lista para cada fila.

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

Una alternativa genérica, utilizando sólo tres líneas

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

Pero si la consulta no devuelve nada, darán lugar a error. En este caso...

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

o

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

pensé que responder a esta pregunta, aunque la respuesta se menciona en parte en las dos respuestas de Adán Schmideg y Alex Martelli de. para que otros como yo que tienen la misma pregunta encuentren la respuesta fácilmente.

conn = sqlite3.connect(":memory:") 
conn.row_factory = sqlite3.Row#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) 
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

versión más corta:

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

Esto funcionó muy bien para mí. ¡Gracias! –

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) 

El resultado es sin duda cierto, pero no sé el mejor.

1

más rápido en mis pruebas:

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) 

usted decide :)

Cuestiones relacionadas