Wie serialisieren ich Pyodbc Ausgabe Cursor (von .fetchone
, .fetchmany
oder .fetchall
) als Python - Wörterbuch?
Ich verwende Bottlepy und muss dict zurückgeben, damit es als JSON zurückgegeben werden kann.
Wie serialisieren ich Pyodbc Ausgabe Cursor (von .fetchone
, .fetchmany
oder .fetchall
) als Python - Wörterbuch?
Ich verwende Bottlepy und muss dict zurückgeben, damit es als JSON zurückgegeben werden kann.
Antworten:
Wenn Sie Spalten nicht im Voraus kennen , erstellen Sie mit Cursor.description eine Liste mit Spaltennamen und komprimieren Sie mit jeder Zeile, um eine Liste mit Wörterbüchern zu erstellen. Beispiel: Angenommen, Verbindung und Abfrage werden erstellt:
>>> cursor = connection.cursor().execute(sql)
>>> columns = [column[0] for column in cursor.description]
>>> print(columns)
['name', 'create_date']
>>> results = []
>>> for row in cursor.fetchall():
... results.append(dict(zip(columns, row)))
...
>>> print(results)
[{'create_date': datetime.datetime(2003, 4, 8, 9, 13, 36, 390000), 'name': u'master'},
{'create_date': datetime.datetime(2013, 1, 30, 12, 31, 40, 340000), 'name': u'tempdb'},
{'create_date': datetime.datetime(2003, 4, 8, 9, 13, 36, 390000), 'name': u'model'},
{'create_date': datetime.datetime(2010, 4, 2, 17, 35, 8, 970000), 'name': u'msdb'}]
cursor.description
. Das hat mir nur eine Menge Zeit gespart.
Mit dem Ergebnis von @ Beargle und Bottlepy konnte ich diese sehr präzise Abfrage erstellen, die den Endpunkt verfügbar macht:
@route('/api/query/<query_str>')
def query(query_str):
cursor.execute(query_str)
return {'results':
[dict(zip([column[0] for column in cursor.description], row))
for row in cursor.fetchall()]}
Hier ist eine Kurzversion, die Sie möglicherweise verwenden können
>>> cursor.select("<your SQL here>")
>>> single_row = dict(zip(zip(*cursor.description)[0], cursor.fetchone()))
>>> multiple_rows = [dict(zip(zip(*cursor.description)[0], row)) for row in cursor.fetchall()]
Wie Sie vielleicht wissen, entfernen Sie beim Hinzufügen von * zu einer Liste die Liste im Grunde genommen und belassen die einzelnen Listeneinträge als Parameter für die von Ihnen aufgerufene Funktion. Mit dem Reißverschluss wählen wir den 1. bis n-Eintrag und reißen sie zusammen wie einen Reißverschluss in Ihrer Hose.
also mit
zip(*[(a,1,2),(b,1,2)])
# interpreted by python as zip((a,1,2),(b,1,2))
du erhältst
[('a', 'b'), (1, 1), (2, 2)]
Da description ein Tupel mit Tupeln ist, wobei jedes Tupel den Header und den Datentyp für jede Spalte beschreibt, können Sie das erste jedes Tupels mit extrahieren
>>> columns = zip(*cursor.description)[0]
gleichwertig
>>> columns = [column[0] for column in cursor.description]
TypeError: 'zip' object is not subscriptable
, also kann ich den zip(*description)[0]
Trick nicht anwenden .
columns
Variablen gespeichert , aber die Komplexität der Funktion multipliziert, indem Sie die
Hauptsächlich ging ich von der @ Torxed-Antwort aus und erstellte einen vollständigen allgemeinen Satz von Funktionen, um das Schema und die Daten in einem Wörterbuch zu finden:
def schema_dict(cursor):
cursor.execute("SELECT sys.objects.name, sys.columns.name FROM sys.objects INNER JOIN sys.columns ON sys.objects.object_id = sys.columns. object_id WHERE sys.objects.type = 'U';")
schema = {}
for it in cursor.fetchall():
if it[0] not in schema:
schema[it[0]]={'scheme':[]}
else:
schema[it[0]]['scheme'].append(it[1])
return schema
def populate_dict(cursor, schema):
for i in schema.keys():
cursor.execute("select * from {table};".format(table=i))
for row in cursor.fetchall():
colindex = 0
for col in schema[i]['scheme']:
if not 'data' in schema[i]:
schema[i]['data']=[]
schema[i]['data'].append(row[colindex])
colindex += 1
return schema
def database_to_dict():
cursor = connect()
schema = populate_dict(cursor, schema_dict(cursor))
Fühlen Sie sich frei, alles Code-Golf zu spielen, um die Linien zu reduzieren; aber in der Zwischenzeit funktioniert es!
;)
In Situationen, in denen der Cursor nicht verfügbar ist, z. B. wenn die Zeilen durch einen Funktionsaufruf oder eine innere Methode zurückgegeben wurden, können Sie mithilfe von row.cursor_description dennoch eine Wörterbuchdarstellung erstellen
def row_to_dict(row):
return dict(zip([t[0] for t in row.cursor_description], row))
Ich weiß, dass diese Frage alt ist, aber sie hat mir geholfen, herauszufinden, wie ich das tun soll, was ich brauche, was sich geringfügig von dem unterscheidet, was OP verlangt. Deshalb dachte ich, ich würde sie teilen, um allen anderen zu helfen, die das brauchen, was ich brauchte: Wenn Wenn Sie eine Routine, die SQL Select-Abfragen ausführt, vollständig verallgemeinern möchten, müssen Sie die Ergebnisse jedoch anhand einer Indexnummer und nicht anhand eines Namens referenzieren. Sie können dies mit einer Liste von Listen anstelle eines Wörterbuchs tun. Jede Zeile der zurückgegebenen Daten wird in der zurückgegebenen Liste als Liste der Feldwerte (Spaltenwerte) dargestellt. Die Spaltennamen können als erster Eintrag der zurückgegebenen Liste angegeben werden, sodass das Parsen der zurückgegebenen Liste in der aufrufenden Routine sehr einfach und flexibel sein kann. Auf diese Weise muss die Routine, die den Datenbankaufruf ausführt, nichts über die Daten wissen, die sie verarbeitet. Hier ist eine solche Routine:
def read_DB_Records(self, tablename, fieldlist, wherefield, wherevalue) -> list:
DBfile = 'C:/DATA/MyDatabase.accdb'
# this connection string is for Access 2007, 2010 or later .accdb files
conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ='+DBfile)
cursor = conn.cursor()
# Build the SQL Query string using the passed-in field list:
SQL = "SELECT "
for i in range(0, len(fieldlist)):
SQL = SQL + "[" + fieldlist[i] + "]"
if i < (len(fieldlist)-1):
SQL = SQL + ", "
SQL = SQL + " FROM " + tablename
# Support an optional WHERE clause:
if wherefield != "" and wherevalue != "" :
SQL = SQL + " WHERE [" + wherefield + "] = " + "'" + wherevalue + "';"
results = [] # Create the results list object
cursor.execute(SQL) # Execute the Query
# (Optional) Get a list of the column names returned from the query:
columns = [column[0] for column in cursor.description]
results.append(columns) # append the column names to the return list
# Now add each row as a list of column data to the results list
for row in cursor.fetchall(): # iterate over the cursor
results.append(list(row)) # add the row as a list to the list of lists
cursor.close() # close the cursor
conn.close() # close the DB connection
return results # return the list of lists
Ich mag @ bryan und @ foo-stack Antworten. Wenn Sie mit postgresql arbeiten und es verwenden, können psycopg2
Sie einige Extras von psycopg2 verwenden , um dasselbe zu erreichen, indem Sie DictCursor
beim Erstellen Ihres Cursors aus der Verbindung Folgendes angeben :
cur = conn.cursor( cursor_factory=psycopg2.extras.DictCursor )
Jetzt können Sie Ihre SQL-Abfrage ausführen und erhalten ein Wörterbuch zum Abrufen Ihrer Ergebnisse, ohne sie manuell zuordnen zu müssen.
cur.execute( sql_query )
results = cur.fetchall()
for row in results:
print row['row_no']
Bitte beachten Sie, import psycopg2.extras
dass dies erforderlich ist.
Angenommen, Sie kennen Ihre Spaltennamen! Außerdem gibt es hier drei verschiedene Lösungen, die
Sie wahrscheinlich als letzte ansehen möchten!
colnames = ['city', 'area', 'street']
data = {}
counter = 0
for row in x.fetchall():
if not counter in data:
data[counter] = {}
colcounter = 0
for colname in colnames:
data[counter][colname] = row[colcounter]
colcounter += 1
counter += 1
Das ist eine indizierte Version, nicht die schönste Lösung, aber sie wird funktionieren. Eine andere Möglichkeit wäre, den Spaltennamen als Wörterbuchschlüssel mit einer Liste in jedem Schlüssel zu indizieren, die die Daten in der Reihenfolge der Zeilennummer enthält. indem Sie tun:
colnames = ['city', 'area', 'street']
data = {}
for row in x.fetchall():
colindex = 0
for col in colnames:
if not col in data:
data[col] = []
data[col].append(row[colindex])
colindex += 1
Wenn ich das schreibe, verstehe ich, dass das Tun for col in colnames
durch ersetzt werden könntefor colindex in range(0, len())
aber Sie bekommen die Idee. Das spätere Beispiel wäre nützlich, wenn nicht alle Daten, sondern jeweils eine Zeile abgerufen werden sollen, zum Beispiel:
def fetchone_dict(stuff):
colnames = ['city', 'area', 'street']
data = {}
for colindex in range(0, colnames):
data[colnames[colindex]] = stuff[colindex]
return data
row = x.fetchone()
print fetchone_dict(row)['city']
Tabellennamen bekommen (ich denke .. dank Foo Stack):
eine direktere Lösung von Beargle unten!
cursor.execute("SELECT sys.objects.name, sys.columns.name FROM sys.objects INNER JOIN sys.columns ON sys.objects.object_id = sys.columns. object_id WHERE sys.objects.type = 'U';")
schema = {}
for it in cursor.fetchall():
if it[0] in schema:
schema[it[0]].append(it[1])
else:
schema[it[0]] = [it[1]]
cursor.execute("SELECT sys.objects.name, sys.columns.name FROM sys.objects INNER JOIN sys.columns ON sys.objects.object_id = sys.columns. object_id WHERE sys.objects.type = 'U';") schema = {} for it in cursor.fetchall(): if it[0] in schema: schema[it[0]].append(it[1]) else: schema[it[0]] = [it[1]]