Come convertire il risultato della query SQL nella struttura dati PANDAS?


116

Qualsiasi aiuto su questo problema sarà molto apprezzato.

Quindi in pratica voglio eseguire una query sul mio database SQL e memorizzare i dati restituiti come struttura dati Pandas.

Ho allegato il codice per la query.

Sto leggendo la documentazione su Panda, ma ho problemi a identificare il tipo di ritorno della mia query.

Ho provato a stampare il risultato della query, ma non fornisce alcuna informazione utile.

Grazie!!!!

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)

Quindi voglio capire qual è il formato / tipo di dati della mia variabile "resoverall" e come metterla con la struttura dati PANDAS.


Fondamentalmente, qual è la struttura / tipo di variabile "resoverall" e come convertirla nella struttura dati di Panda.
user1613017

Pandas sembra piuttosto interessante, non ne avevo mai sentito parlare prima, ma questa domanda non ha quasi senso. Puoi provare a chiarire cosa intendi per "non fornisce alcuna informazione utile"?
tadman

1
Perché la query che ho eseguito dà un ritorno, mi chiedo solo come dovrei manipolare questo ritorno e trasformarlo in una struttura dati panda. Sono molto nuovo in Python e quindi non ho molta conoscenza, come quello che facciamo in PHP è solo per fare un sql_fetch_array e abbiamo dati "utilizzabili". =)
user1613017

Risposte:


120

Ecco il codice più breve che farà il lavoro:

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

Puoi andare più elaborato e analizzare i tipi come nella risposta di Paul.


1
Questo ha funzionato per me per 1.000.000 di record ricavati da un database Oracle.
Erdem KAYA

8
df = DataFrame(cursor.fetchall())restituisce ValueError: DataFrame constructor not properly called!, sembra che la tupla di tuple non sia accettabile per il costruttore DataFrame. Inoltre, non è presente alcun .keys()cursore né in modalità dizionario né in modalità tupla.
Mobigital

3
Tieni presente che il metodo delle chiavi funzionerà solo con i risultati ottenuti utilizzando sqlalchemy. Pyodbc utilizza l'attributo descrizione per le colonne.
Filip

Può funzionare per i database Postgres? Sto cercando di ottenere i nomi delle colonne per il dataframe dei risultati con la keys()funzione ma non riesco a farlo funzionare.
Bowen Liu,

1
@BowenLiu Sì, puoi usarlo con psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff

137

Modifica: marzo 2015

Come indicato di seguito, i panda ora utilizzano SQLAlchemy sia per leggere da ( read_sql ) che per inserire ( to_sql ) un database. Quanto segue dovrebbe funzionare

import pandas as pd

df = pd.read_sql(sql, cnxn)

Risposta precedente: Via mikebmassey da una domanda simile

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

Questo sembra essere il modo migliore per farlo, poiché non è necessario utilizzare manualmente .keys () per ottenere l'indice della colonna. Probabilmente la risposta di Daniel è stata scritta prima che esistesse questo metodo. Puoi anche usare pandas.io.sql.read_frame ()
RobinL

1
@openwonk dove sarebbe implementato pd.read_sql()nello snippet di codice sopra?
3kstc

In realtà, dalla mia ultima risposta, ho usato pyodbce pandasinsieme un bel po '. Aggiunta di una nuova risposta con l'esempio, FYI.
openwonk

33

Se stai usando l'ORM di SQLAlchemy invece del linguaggio delle espressioni, potresti ritrovarti a voler convertire un oggetto di tipo sqlalchemy.orm.query.Queryin un frame di dati Pandas.

L'approccio più pulito consiste nell'ottenere l'SQL generato dall'attributo dell'istruzione della query e quindi eseguirlo con il read_sql()metodo di pandas . Ad esempio, a partire da un oggetto Query chiamato query:

df = pd.read_sql(query.statement, query.session.bind)

5
Un approccio più efficiente consiste nell'ottenere l'istruzione da sqlalchemy e lasciare che i panda eseguano la query stessa pandas.read_sql_query, passando query.statementad essa. Vedere questa risposta: stackoverflow.com/a/29528804/1273938
LeoRochael

Grazie @LeoRochael! Ho modificato la mia risposta. Decisamente più pulito!
Nathan Gould

23

Modifica 30/09/2014:

Panda ora ha una read_sqlfunzione. Sicuramente vuoi usarlo invece.

Risposta originale:

Non posso aiutarti con SQLAlchemy: uso sempre pyodbc, MySQLdb o psychopg2 secondo necessità. Ma quando lo faccio, una funzione semplice come quella di seguito tende a soddisfare le mie esigenze:

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

Penso che tu debba importare i decimali da qualche parte in alto?
joe dal

@joefromct Forse, ma questa risposta è così obsoleta che dovrei davvero colpire tutto e mostrare i metodi dei panda.
Paul H

Può essere relevent per qualche ... La ragione per cui stava studiando questo è stato a causa della mia altra questione, utilizzando read_sql () qui stackoverflow.com/questions/32847246/...
joefromct

È rilevante per coloro che non possono utilizzare SQLAlchemy che non supporta tutti i database.
lamecicle

@lamecicle in qualche modo in disaccordo. IIRC, read_sqlpuò ancora accettare connessioni non SQLAlchemy tramite, ad esempio, pyodbc, psychopg2, ecc.
Paul H

16

Connettore MySQL

Per quelli che funzionano con il connettore mysql puoi usare questo codice come inizio. (Grazie a @Daniel Velkov)

Rif. Usati:


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

9

Ecco il codice che uso. Spero che questo ti aiuti.

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)

9

Questa è una risposta breve e chiara al tuo problema:

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)

9

1. Utilizzo di 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. Utilizzo di 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)

risposta semplice e ottima!
Lucas Aimaretto

5

Come Nathan, spesso voglio scaricare i risultati di una query sqlalchemy o sqlsoup in un frame di dati Pandas. La mia soluzione per questo è:

query = session.query(tbl.Field1, tbl.Field2)
DataFrame(query.all(), columns=[column['name'] for column in query.column_descriptions])

1
Se hai un oggetto query. È più efficiente ottenere l'istruzione da sqlalchemy e lasciare che i panda eseguano la query da soli pandas.read_sql_query, passando query.statementad essa. Vedere questa risposta: stackoverflow.com/a/29528804/1273938
LeoRochael

4

resoverallè un oggetto ResultProxy di sqlalchemy. Puoi leggere di più a riguardo nei documenti di sqlalchemy , quest'ultimo spiega l'utilizzo di base del lavoro con motori e connessioni. Importante qui è che resoverallè proprio come.

Ai panda piacciono gli oggetti dict like per creare le proprie strutture dati, vedere i documenti online

Buona fortuna con sqlalchemy e panda.


4

Basta usare pandase pyodbcinsieme. Dovrai modificare la stringa di connessione ( connstr) in base alle specifiche del database.

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

L'ho utilizzato pyodbccon diversi database aziendali (ad esempio SQL Server, MySQL, MariaDB, IBM).


Come riscrivere questo dataframe su MSSQL usando Pyodbc? Diversamente dall'uso di sqlalchemy
Ramsey

Usa il to_sqlmetodo DataFramesull'oggetto. Il metodo predefinito è SQLite, quindi devi passargli esplicitamente un oggetto che punta al database MSSQL. Vedi i documenti .
openwonk

Ho provato quello sotto e ho circa 200.000 righe con 13 colonne. Anche dopo 15 minuti non si completa. Qualche idea? df.to_sql ('tablename', engine, schema = 'schemaname', if_exists = 'append', index = False)
Ramsey

Sembra lento ... probabilmente avrei bisogno di vedere l'intero codice in azione, mi dispiace. Vorrei pandasfosse più ottimizzato per il lavoro ETL leggero, ma ahimè ...
openwonk

3

Questa domanda è vecchia, ma volevo aggiungere i miei due centesimi. Ho letto la domanda come "Voglio eseguire una query sul mio [mio] database SQL e memorizzare i dati restituiti come struttura dati Pandas [DataFrame]".

Dal codice sembra che tu intenda database mysql e presumi che intendi panda DataFrame.

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)

Per esempio,

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

Questo importerà tutte le righe di testTable in un DataFrame.


1

Ecco il mio. Per ogni evenienza, se stai usando "pymysql":

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

1

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

Dovrebbe cambiare per utilizzare pandas.DataFrame.to_sql https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

C'è un'altra soluzione. Da PYODBC a Panda - DataFrame non funziona - La forma dei valori passati è (x, y), gli indici implicano (w, z)

A partire da Pandas 0.12 (credo) puoi fare:

import pandas
import pyodbc

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

data = pandas.read_sql(sql, cnn)

Prima della 0.12, potresti fare:

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

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

data = read_frame(sql, cnn)

Questo è di gran lunga il modo più semplice
Wilmer E. Henao

0

Molto tempo dall'ultimo post ma forse aiuta qualcuno ...

In corto rispetto a Paul H:

my_dic = session.query(query.all())
my_df = pandas.DataFrame.from_dict(my_dic)

0

il modo migliore per farlo

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

0

Se il tipo di risultato è ResultSet , è necessario convertirlo prima in dizionario. Quindi le colonne DataFrame verranno raccolte automaticamente.

Questo funziona sul mio caso:

df = pd.DataFrame([dict(r) for r in resoverall])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.