Wie konvertiere ich ein SQL Query-Ergebnis in eine PANDAS-Datenstruktur?

116

Jede Hilfe zu diesem Problem wird sehr geschätzt.

Grundsätzlich möchte ich eine Abfrage in meiner SQL-Datenbank ausführen und die zurückgegebenen Daten als Pandas-Datenstruktur speichern.

Ich habe Code für die Abfrage angehängt.

Ich lese die Dokumentation zu Pandas, habe jedoch Probleme, den Rückgabetyp meiner Abfrage zu ermitteln.

Ich habe versucht, das Abfrageergebnis zu drucken, aber es enthält keine nützlichen Informationen.

Vielen Dank!!!!

from sqlalchemy import create_engine

engine2 = create_engine('mysql://THE DATABASE I AM ACCESSING')
connection2 = engine2.connect()
dataid = 1022
resoverall = connection2.execute("
  SELECT 
      sum(BLABLA) AS BLA,
      sum(BLABLABLA2) AS BLABLABLA2,
      sum(SOME_INT) AS SOME_INT,
      sum(SOME_INT2) AS SOME_INT2,
      100*sum(SOME_INT2)/sum(SOME_INT) AS ctr,
      sum(SOME_INT2)/sum(SOME_INT) AS cpc
   FROM daily_report_cooked
   WHERE campaign_id = '%s'", %dataid)

Ich möchte also irgendwie verstehen, was das Format / der Datentyp meiner Variablen "resoverall" ist und wie ich sie in die PANDAS-Datenstruktur einfügen soll.

user1613017
quelle
Was ist im Grunde die Struktur / der Typ der "Resoverall" -Variablen und wie wird sie in die Pandas-Datenstruktur konvertiert?
user1613017
Pandas klingt ziemlich interessant, ich hatte noch nie davon gehört, aber diese Frage macht kaum Sinn. Können Sie versuchen zu klären, was Sie unter "gibt keine nützlichen Informationen" verstehen?
Tadman
1
Da die von mir ausgeführte Abfrage eine Rückgabe ergibt, frage ich mich nur, wie ich diese Rückgabe manipulieren und in eine Pandas-Datenstruktur verwandeln soll. Ich bin sehr neu in Python und habe daher nicht viel Wissen. Was wir in PHP tun, ist nur ein sql_fetch_array zu machen und wir haben "verwendbare" Daten. =)
user1613017

Antworten:

120

Hier ist der kürzeste Code, der die Arbeit erledigt:

from pandas import DataFrame
df = DataFrame(resoverall.fetchall())
df.columns = resoverall.keys()

Sie können schicker werden und die Typen wie in Pauls Antwort analysieren.

Daniel Velkov
quelle
1
Dies funktionierte für mich für 1.000.000 Datensätze, die aus einer Oracle-Datenbank stammen.
Erdem KAYA
8
df = DataFrame(cursor.fetchall())ValueError: DataFrame constructor not properly called!Wenn Sie zurückkehren , scheint das Tupel der Tupel für den DataFrame-Konstruktor nicht akzeptabel zu sein. Es gibt auch keinen .keys()Cursor im Wörterbuch- oder Tupelmodus.
Mobigital
3
Beachten Sie nur, dass die Schlüsselmethode nur mit Ergebnissen funktioniert, die mit sqlalchemy erzielt wurden. Pyodbc verwendet das Beschreibungsattribut für Spalten.
Filip
Kann dies für Postgres-Datenbanken funktionieren? Ich versuche, Spaltennamen für den Ergebnisdatenrahmen mit keys()Funktion abzurufen , kann ihn jedoch nicht zum Laufen bringen.
Bowen Liu
1
@BowenLiu Ja, Sie können mit psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff
136

Bearbeiten: März 2015

Wie unten erwähnt, verwendet pandas jetzt SQLAlchemy, um sowohl aus ( read_sql ) zu lesen als auch in ( to_sql ) eine Datenbank einzufügen . Folgendes sollte funktionieren

import pandas as pd

df = pd.read_sql(sql, cnxn)

Vorherige Antwort: Über mikebmassey aus einer ähnlichen Frage

import pyodbc
import pandas.io.sql as psql

cnxn = pyodbc.connect(connection_info) 
cursor = cnxn.cursor()
sql = "SELECT * FROM TABLE"

df = psql.frame_query(sql, cnxn)
cnxn.close()
Bart
quelle
Dies scheint der beste Weg zu sein, da Sie .keys () nicht manuell verwenden müssen, um den Spaltenindex abzurufen. Wahrscheinlich wurde Daniels Antwort geschrieben, bevor diese Methode existierte. Sie können auch pandas.io.sql.read_frame ()
RobinL
1
@openwonk wo würde pd.read_sql()im obigen Code-Snippet implementiert ?
3kstc
Eigentlich seit meiner letzten Antwort, die ich benutzt habe pyodbcund pandaszusammen eine ganze Menge . Hinzufügen einer neuen Antwort mit Beispiel, FYI.
Openwonk
33

Wenn Sie ORM von SQLAlchemy anstelle der Ausdruckssprache verwenden, möchten Sie möglicherweise ein Objekt vom Typ sqlalchemy.orm.query.Queryin einen Pandas- Datenrahmen konvertieren .

Der sauberste Ansatz besteht darin, das generierte SQL aus dem Anweisungsattribut der Abfrage abzurufen und es dann mit der read_sql()Methode von pandas auszuführen . Beginnen Sie beispielsweise mit einem Abfrageobjekt mit dem Namen query:

df = pd.read_sql(query.statement, query.session.bind)
Nathan Gould
quelle
5
Ein effizienterer Ansatz besteht darin, die Anweisung von sqlalchemy abzurufen und Pandas die Abfrage selbst ausführen zu lassen pandas.read_sql_queryund query.statementan sie weiterzuleiten . Siehe diese Antwort: stackoverflow.com/a/29528804/1273938
LeoRochael
Danke @LeoRochael! Ich habe meine Antwort bearbeitet. Auf jeden Fall sauberer!
Nathan Gould
23

Bearbeiten 30.09.2014:

Pandas hat jetzt eine read_sqlFunktion. Sie möchten das definitiv stattdessen verwenden.

Ursprüngliche Antwort:

Ich kann Ihnen bei SQLAlchemy nicht helfen - ich verwende nach Bedarf immer pyodbc, MySQLdb oder psychopg2. Dabei entspricht eine so einfache Funktion wie die folgende meinen Anforderungen:

import decimal

import pydobc
import numpy as np
import pandas

cnn, cur = myConnectToDBfunction()
cmd = "SELECT * FROM myTable"
cur.execute(cmd)
dataframe = __processCursor(cur, dataframe=True)

def __processCursor(cur, dataframe=False, index=None):
    '''
    Processes a database cursor with data on it into either
    a structured numpy array or a pandas dataframe.

    input:
    cur - a pyodbc cursor that has just received data
    dataframe - bool. if false, a numpy record array is returned
                if true, return a pandas dataframe
    index - list of column(s) to use as index in a pandas dataframe
    '''
    datatypes = []
    colinfo = cur.description
    for col in colinfo:
        if col[1] == unicode:
            datatypes.append((col[0], 'U%d' % col[3]))
        elif col[1] == str:
            datatypes.append((col[0], 'S%d' % col[3]))
        elif col[1] in [float, decimal.Decimal]:
            datatypes.append((col[0], 'f4'))
        elif col[1] == datetime.datetime:
            datatypes.append((col[0], 'O4'))
        elif col[1] == int:
            datatypes.append((col[0], 'i4'))

    data = []
    for row in cur:
        data.append(tuple(row))

    array = np.array(data, dtype=datatypes)
    if dataframe:
        output = pandas.DataFrame.from_records(array)

        if index is not None:
            output = output.set_index(index)

    else:
        output = array

    return output
Paul H.
quelle
Ich denke, Sie müssen irgendwo oben Dezimalstellen importieren?
Joe vom
@joefromct Vielleicht, aber diese Antwort ist so veraltet, dass ich wirklich nur das Ganze streichen sollte und die Pandas-Methoden zeige.
Paul H
Es kann für einige relevant sein ... der Grund, warum ich dies studierte, war wegen meines anderen Problems, das read_sql () hier verwendet hat stackoverflow.com/questions/32847246/…
joefromct
Es ist relevant für diejenigen, die SQLAlchemy nicht verwenden können, das nicht alle Datenbanken unterstützt.
Lamecicle
@lamecicle etwas nicht einverstanden. IIRC read_sqlkann weiterhin Nicht-SQLAlchemy-Verbindungen akzeptieren, z. B. durch pyodbc, psychopg2 usw.
Paul H
16

MySQL Connector

Für diejenigen, die mit dem MySQL-Connector arbeiten, können Sie diesen Code als Start verwenden. (Danke an @Daniel Velkov)

Gebrauchte Refs:


import pandas as pd
import mysql.connector

# Setup MySQL connection
db = mysql.connector.connect(
    host="<IP>",              # your host, usually localhost
    user="<USER>",            # your username
    password="<PASS>",        # your password
    database="<DATABASE>"     # name of the data base
)   

# You must create a Cursor object. It will let you execute all the queries you need
cur = db.cursor()

# Use all the SQL you like
cur.execute("SELECT * FROM <TABLE>")

# Put it all to a data frame
sql_data = pd.DataFrame(cur.fetchall())
sql_data.columns = cur.column_names

# Close the session
db.close()

# Show the data
print(sql_data.head())
Thomas Devoogdt
quelle
9

Hier ist der Code, den ich benutze. Hoffe das hilft.

import pandas as pd
from sqlalchemy import create_engine

def getData():
  # Parameters
  ServerName = "my_server"
  Database = "my_db"
  UserPwd = "user:pwd"
  Driver = "driver=SQL Server Native Client 11.0"

  # Create the connection
  engine = create_engine('mssql+pyodbc://' + UserPwd + '@' + ServerName + '/' + Database + "?" + Driver)

  sql = "select * from mytable"
  df = pd.read_sql(sql, engine)
  return df

df2 = getData()
print(df2)
Murali Bala
quelle
9

Dies ist eine kurze und klare Antwort auf Ihr Problem:

from __future__ import print_function
import MySQLdb
import numpy as np
import pandas as pd
import xlrd

# Connecting to MySQL Database
connection = MySQLdb.connect(
             host="hostname",
             port=0000,
             user="userID",
             passwd="password",
             db="table_documents",
             charset='utf8'
           )
print(connection)
#getting data from database into a dataframe
sql_for_df = 'select * from tabledata'
df_from_database = pd.read_sql(sql_for_df , connection)
DeshDeep Singh
quelle
8

1. Verwenden von MySQL-connector-python

# pip install mysql-connector-python

import mysql.connector
import pandas as pd

mydb = mysql.connector.connect(
    host = 'host',
    user = 'username',
    passwd = 'pass',
    database = 'db_name'
)
query = 'select * from table_name'
df = pd.read_sql(query, con = mydb)
print(df)

2. Verwenden von SQLAlchemy

# pip install pymysql
# pip install sqlalchemy

import pandas as pd
import sqlalchemy

engine = sqlalchemy.create_engine('mysql+pymysql://username:password@localhost:3306/db_name')

query = '''
select * from table_name
'''
df = pd.read_sql_query(query, engine)
print(df)
Lintang Wisesa
quelle
einfache und gute Antwort!
Lucas Aimaretto
5

Wie Nathan möchte ich häufig die Ergebnisse einer SQLalchemie- oder SQLSoup-Abfrage in einem Pandas-Datenrahmen speichern. Meine eigene Lösung dafür ist:

query = session.query(tbl.Field1, tbl.Field2)
DataFrame(query.all(), columns=[column['name'] for column in query.column_descriptions])
Janak Mayer
quelle
1
Wenn Sie ein Abfrageobjekt haben. Es ist effizienter, die Anweisung von sqlalchemy abzurufen und Pandas die Abfrage selbst ausführen zu lassen pandas.read_sql_queryund query.statementan sie weiterzuleiten . Siehe diese Antwort: stackoverflow.com/a/29528804/1273938
LeoRochael
4

resoverallist ein sqlalchemy ResultProxy-Objekt. Weitere Informationen finden Sie in den sqlalchemy-Dokumenten . Letzteres erläutert die grundlegende Verwendung der Arbeit mit Engines und Connections. Wichtig ist hier, dass resoveralldiktiert wird.

Pandas diktieren gerne Objekte, um ihre Datenstrukturen zu erstellen. Weitere Informationen finden Sie in den Online-Dokumenten

Viel Glück mit sqlalchemy und Pandas.

Wouter Overmeire
quelle
4

Einfach benutzen pandasund pyodbczusammen. Sie müssen Ihre Verbindungszeichenfolge ( connstr) gemäß Ihren Datenbankspezifikationen ändern .

import pyodbc
import pandas as pd

# MSSQL Connection String Example
connstr = "Server=myServerAddress;Database=myDB;User Id=myUsername;Password=myPass;"

# Query Database and Create DataFrame Using Results
df = pd.read_sql("select * from myTable", pyodbc.connect(connstr))

Ich habe pyodbcmit mehreren Unternehmensdatenbanken (z. B. SQL Server, MySQL, MariaDB, IBM) verwendet.

openwonk
quelle
Wie schreibe ich diesen Datenrahmen mit Pyodbc wieder zurück in MSSQL? Andere als mit sqlalchemy
Ramsey
Verwenden Sie die to_sqlMethode für das DataFrameObjekt. Diese Methode ist standardmäßig SQLite, daher müssen Sie ihr explizit ein Objekt übergeben, das auf die MSSQL-Datenbank verweist. Siehe Dokumente .
Openwonk
Ich habe das folgende versucht und ich habe ungefähr 200K Zeilen mit 13 Spalten. Es ist auch nach 15 Minuten nicht abgeschlossen. Irgendwelche Ideen? df.to_sql ('Tabellenname', Engine, Schema = 'Schemaname', if_exists = 'Anhängen', Index = False)
Ramsey
Das scheint langsam zu sein ... Ich müsste wahrscheinlich den gesamten Code in Aktion sehen, sorry. Ich wünschte, wäre pandasmehr für leichte ETL-Arbeit optimiert, aber leider ...
openwonk
3

Diese Frage ist alt, aber ich wollte meine zwei Cent hinzufügen. Ich las die Frage als "Ich möchte eine Abfrage an meine [meine] SQL-Datenbank ausführen und die zurückgegebenen Daten als Pandas-Datenstruktur [DataFrame] speichern."

Aus dem Code geht hervor, dass Sie MySQL-Datenbank meinen und davon ausgehen, dass Sie Pandas DataFrame meinen.

import MySQLdb as mdb
import pandas.io.sql as sql
from pandas import *

conn = mdb.connect('<server>','<user>','<pass>','<db>');
df = sql.read_frame('<query>', conn)

Beispielsweise,

conn = mdb.connect('localhost','myname','mypass','testdb');
df = sql.read_frame('select * from testTable', conn)

Dadurch werden alle Zeilen von testTable in einen DataFrame importiert.

BubbleGuppies
quelle
1

Hier ist mein. Nur für den Fall, dass Sie "pymysql" verwenden:

import pymysql
from pandas import DataFrame

host   = 'localhost'
port   = 3306
user   = 'yourUserName'
passwd = 'yourPassword'
db     = 'yourDatabase'

cnx    = pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=db)
cur    = cnx.cursor()

query  = """ SELECT * FROM yourTable LIMIT 10"""
cur.execute(query)

field_names = [i[0] for i in cur.description]
get_data = [xx for xx in cur]

cur.close()
cnx.close()

df = DataFrame(get_data)
df.columns = field_names
kennyut
quelle
1

pandas.io.sql.write_frame ist DEPRECATED. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Sollte sich ändern, um pandas.DataFrame.to_sql zu verwenden https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html zu verwenden

Es gibt eine andere Lösung. PYODBC zu Pandas - DataFrame funktioniert nicht - Die Form der übergebenen Werte ist (x, y), Indizes implizieren (w, z)

Ab Pandas 0.12 (glaube ich) können Sie Folgendes tun:

import pandas
import pyodbc

sql = 'select * from table'
cnn = pyodbc.connect(...)

data = pandas.read_sql(sql, cnn)

Vor 0.12 konnten Sie Folgendes tun:

import pandas
from pandas.io.sql import read_frame
import pyodbc

sql = 'select * from table'
cnn = pyodbc.connect(...)

data = read_frame(sql, cnn)
江明哲
quelle
Dies ist bei weitem der einfachste Weg
Wilmer E. Henao
0

Lange Zeit vom letzten Beitrag, aber vielleicht hilft es jemandem ...

Kurzweg als Paul H:

my_dic = session.query(query.all())
my_df = pandas.DataFrame.from_dict(my_dic)
Antonio Fernandez
quelle
0

am besten mache ich das

db.execute(query) where db=db_class() #database class
    mydata=[x for x in db.fetchall()]
    df=pd.DataFrame(data=mydata)
Berto
quelle
0

Wenn der Ergebnistyp ResultSet ist , sollten Sie ihn zuerst in ein Wörterbuch konvertieren. Dann werden die DataFrame-Spalten automatisch erfasst.

Das funktioniert in meinem Fall:

df = pd.DataFrame([dict(r) for r in resoverall])
tanza9
quelle