Und ja, ich habe bemerkt, dass dies in den FAQ für PEPE249 steht , aber das ändert nichts an meiner Anforderung.
Foo Stack
Antworten:
159
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:
wusste nicht über cursor.description. Das hat mir nur eine Menge Zeit gespart.
TehTris
benötigt, um Klammern um print (Spalten) und print (Ergebnisse) zu wickeln, damit dies funktioniert
LJT
2
@LJT Nur in Python3 ... aber da die Funktion print () in Python2 funktioniert, empfiehlt es sich, sie zu verwenden.
Auspex
1
@ BenLutgens Da das Beispiel eine Liste von Diktaten erzeugt , kein Diktat.
Auspex
1
Update: Standardmäßig setzt pypyodbc Kleinbuchstaben = True. Sie können dies folgendermaßen überschreiben: import pypyodbc; pypyodbc.lowercase = False. Referenz: Link
Weihui Guo
13
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>')defquery(query_str):
cursor.execute(query_str)
return {'results':
[dict(zip([column[0] for column in cursor.description], row))
for row in cursor.fetchall()]}
@ Ben Ja! Sie sollten es niemals verwenden, es sei denn, Sie sind zu 1000% sicher, dass die Anforderungen immer von einem vertrauenswürdigen Client stammen.
Bora M. Alper
6
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]
Mit python3.4 bekomme ich : TypeError: 'zip' object is not subscriptable, also kann ich den zip(*description)[0]Trick nicht anwenden .
Malat
In Python 3.4 ist zip ein Iterator. Sie können die Postleitzahl in eine Listenliste einschließen (Postleitzahl (* Beschreibung)) [0] @malat
Tommy Strand
Sie haben eine Zeile mit columnsVariablen gespeichert , aber die Komplexität der Funktion multipliziert, indem Sie die
Spaltennamen
3
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:
defschema_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] notin schema:
schema[it[0]]={'scheme':[]}
else:
schema[it[0]]['scheme'].append(it[1])
return schema
defpopulate_dict(cursor, schema):for i in schema.keys():
cursor.execute("select * from {table};".format(table=i))
for row in cursor.fetchall():
colindex = 0for col in schema[i]['scheme']:
ifnot'data'in schema[i]:
schema[i]['data']=[]
schema[i]['data'].append(row[colindex])
colindex += 1return schema
defdatabase_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
defrow_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:
defread_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 listfor 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 connectionreturn results # return the list of lists
Ich mag @ bryan und @ foo-stack Antworten. Wenn Sie mit postgresql arbeiten und es verwenden, können psycopg2Sie einige Extras von psycopg2 verwenden , um dasselbe zu erreichen, indem Sie DictCursorbeim 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.extrasdass 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 = 0for row in x.fetchall():
ifnot counter in data:
data[counter] = {}
colcounter = 0for 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 = 0for col in colnames:
ifnot col in data:
data[col] = []
data[col].append(row[colindex])
colindex += 1
Wenn ich das schreibe, verstehe ich, dass das Tun for col in colnamesdurch 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:
Verwenden von dict für jede Datenzeile
deffetchone_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]]
Danke, aber gibt es eine allgemeine Lösung, wenn ich meine Spaltennamen nicht kenne?
Foo Stack
Ja, es heißt SQL-Syntax. Sie können Ihre Datenbank nach den Namen der Tabelle abfragen, für die Sie eine Abfrage durchführen. stackoverflow.com/questions/4645456/…
Torxed
Ich habe einen netten kleinen verallgemeinerten Schemasammler geschrieben:
Foo Stack
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]]
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'}]
quelle
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()]}
quelle
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]
quelle
TypeError: 'zip' object is not subscriptable
, also kann ich denzip(*description)[0]
Trick nicht anwenden .columns
Variablen gespeichert , aber die Komplexität der Funktion multipliziert, indem Sie dieHauptsä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!
;)
quelle
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))
quelle
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
quelle
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 SieDictCursor
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.quelle
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:Verwenden von dict für jede Datenzeile
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]]
quelle
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]]