Wie kann ich ein Diktat aus einer SQLite-Abfrage erhalten?


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

Mit der Iteration erhalte ich Listen, die den Zeilen entsprechen.

for row in res:
    print row

Ich kann den Namen der Spalten erhalten

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

Aber gibt es eine Funktion oder Einstellung, um Wörterbücher anstelle von Listen zu erhalten?

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

oder muss ich mich machen



3
@ vy32: Diese Frage stammt aus dem Juli 2010, die Frage, mit der Sie verlinkt haben, ist der November 2010. Das ist also der Betrüger. Und wie zu erwarten war, wurde der umgekehrte Kommentar dazu abgegeben :-)
Aneroid

Antworten:


158

Sie können row_factory verwenden , wie im Beispiel in den Dokumenten:

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

oder befolgen Sie die Ratschläge, die direkt nach diesem Beispiel in den Dokumenten gegeben werden:

Wenn die Rückgabe eines Tupels nicht ausreicht und Sie einen namenbasierten Zugriff auf Spalten wünschen, sollten Sie row_factory auf den hochoptimierten Typ sqlite3.Row setzen. Row bietet sowohl einen indexbasierten als auch einen auf Groß- und Kleinschreibung nicht berücksichtigten namensbasierten Zugriff auf Spalten ohne Speicheraufwand. Es ist wahrscheinlich besser als Ihr eigener wörterbuchbasierter Ansatz oder sogar eine db_row-basierte Lösung.


Wenn Ihre Spaltennamen in ihnen Sonderzeichen haben zum Beispiel SELECT 1 AS "dog[cat]"dann die cursorhaben nicht die korrekte Beschreibung eines dict zu erstellen.
Crazometer

Ich habe eingestellt connection.row_factory = sqlite3.Rowund versucht, connection.row_factory = dict_factorywie gezeigt, aber cur.fetchall()gibt mir immer noch eine Liste von Tupeln - eine Idee, warum dies nicht funktioniert?
Anzeigename

@displayname, nicht in der Dokumentation angegeben "Es wird versucht, ein Tupel in den meisten seiner Funktionen nachzuahmen." Ich bin mir ziemlich sicher, dass es irgendwie ähnlich ist, wie man es bekommen kann collections.namedtuple. Wenn ich benutze, cur.fetchmany()bekomme ich Einträge wie <sqlite3.Row object at 0x...>.
Nur am

Selbst 7 Jahre später ist diese Antwort das hilfreichste Kopieren und Einfügen aus den Dokumenten, die ich auf SO gefunden habe. Vielen Dank!
WillardSolutions

40

Ich dachte, ich beantworte diese Frage, obwohl die Antwort teilweise in den Antworten von Adam Schmideg und Alex Martelli erwähnt wird. Damit andere wie ich, die die gleiche Frage haben, die Antwort leicht finden können.

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
Derzeit fetchall()scheint sqlite3.RowObjekte zurückzugeben. Diese können jedoch einfach mit dict(): in ein Wörterbuch konvertiert werden result = [dict(row) for row in c.fetchall()].
Gonçalo Ribeiro

21

Selbst wenn Sie die Klasse sqlite3.Row verwenden, können Sie die Zeichenfolgenformatierung nicht in der folgenden Form verwenden:

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

Um dies zu überwinden, verwende ich eine Hilfsfunktion, die die Zeile übernimmt und in ein Wörterbuch konvertiert. Ich verwende dies nur, wenn das Wörterbuchobjekt dem Zeilenobjekt vorzuziehen ist (z. B. für Dinge wie die Formatierung von Zeichenfolgen, bei denen das Zeilenobjekt die Wörterbuch-API nicht nativ unterstützt). Verwenden Sie das Row-Objekt jedoch alle anderen Male.

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

9
sqlite3.Row implementiert das Mapping-Protokoll. Sie können einfach tunprint "%(id)i - %(name)s: %(value)s" % dict(row)
Mzzzzzz

9

Nachdem Sie eine Verbindung zu SQLite hergestellt haben, reicht con = sqlite3.connect(.....)es aus, nur Folgendes auszuführen:

con.row_factory = sqlite3.Row

Voila!


8

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

Also ja, mach es selbst.


> variiert zwischen Datenbanken - wie was, SQLite 3.7 und 3.8?
Nucular

@ user1123466: ... Wie zwischen SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird ...
Ignacio Vazquez-Abrams

3

Kürzere Version:

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

3

Am schnellsten bei meinen Tests:

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)

Du entscheidest :)


1

Ähnlich wie die oben genannten Lösungen, aber am kompaktesten:

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

Dies funktionierte für mich, wo die obigen Antworten db.row_factory = sqlite3.Rowfür mich nicht funktionierten (da dies zu einem JSON TypeError führte)
Phillip

1

Wie in der Antwort von @ gandalf erwähnt, muss man verwenden conn.row_factory = sqlite3.Row, aber die Ergebnisse sind keine direkten Wörterbücher. dictIn der letzten Schleife muss eine zusätzliche "Besetzung" hinzugefügt werden :

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

Ich denke, Sie waren auf dem richtigen Weg. Lassen Sie uns dies sehr einfach halten und vervollständigen, was Sie versucht haben:

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)

Der Nachteil ist .fetchall()der Mord an Ihrem Speicherverbrauch , wenn Ihr Tisch sehr groß ist. Für einfache Anwendungen, die nur wenige Tausend Textzeilen und numerische Spalten betreffen, ist dieser einfache Ansatz jedoch ausreichend.

Für ernsthafte Dinge sollten Sie sich Reihenfabriken ansehen, wie in vielen anderen Antworten vorgeschlagen.


0

Oder Sie können die sqlite3.Rows wie folgt in ein Wörterbuch konvertieren. Dies gibt ein Wörterbuch mit einer Liste für jede Zeile.

    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

Eine generische Alternative mit nur drei Zeilen

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

Wenn Ihre Abfrage jedoch nichts zurückgibt, führt dies zu einem Fehler. In diesem Fall...

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

oder

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)

Das Ergebnis ist definitiv wahr, aber ich weiß nicht das Beste.


0

Wörterbücher in Python bieten beliebigen Zugriff auf ihre Elemente. Jedes "Wörterbuch" mit "Namen", obwohl es einerseits informativ sein könnte (auch bekannt als die Feldnamen), "ordnet" die Felder "auf", was möglicherweise unerwünscht ist.

Am besten erhalten Sie die Namen in einer separaten Liste und kombinieren sie bei Bedarf selbst mit den Ergebnissen.

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

Denken Sie auch daran, dass die Namen in allen Ansätzen die Namen sind, die Sie in der Abfrage angegeben haben, nicht die Namen in der Datenbank. Ausnahme ist dieSELECT * FROM

Wenn Sie nur die Ergebnisse mit einem Wörterbuch erhalten möchten, verwenden Sie auf jeden Fall das conn.row_factory = sqlite3.Row(bereits in einer anderen Antwort angegeben).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.