¿Cómo convertir el resultado de la consulta SQL a la estructura de datos PANDAS?

116

Cualquier ayuda sobre este problema será muy apreciada.

Entonces, básicamente, quiero ejecutar una consulta en mi base de datos SQL y almacenar los datos devueltos como estructura de datos Pandas.

He adjuntado el código para la consulta.

Estoy leyendo la documentación sobre Pandas, pero tengo problemas para identificar el tipo de retorno de mi consulta.

Intenté imprimir el resultado de la consulta, pero no proporciona ninguna información útil.

¡¡¡¡Gracias!!!!

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)

Así que quiero entender cuál es el formato / tipo de datos de mi variable "resoverall" y cómo ponerlo con la estructura de datos PANDAS.

user1613017
fuente
Básicamente, cuál es la estructura / tipo de variable "resoverall" y cómo convertirla en la estructura de datos de Pandas.
user1613017
Pandas suena bastante interesante, no había oído hablar de eso antes, pero esta pregunta apenas tiene sentido. ¿Puede intentar aclarar lo que quiere decir con "no proporciona ninguna información útil"?
tadman
1
Debido a que la consulta que he ejecutado da un retorno, solo me pregunto cómo debo manipular este retorno y convertirlo en una estructura de datos de pandas. Soy muy nuevo en Python y por lo tanto no tengo mucho conocimiento, como que lo que hacemos en PHP es simplemente hacer un sql_fetch_array y tenemos datos "utilizables". =)
user1613017

Respuestas:

120

Aquí está el código más corto que hará el trabajo:

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

Puede ir más elegante y analizar los tipos como en la respuesta de Paul.

Daniel Velkov
fuente
1
Esto funcionó para mí para 1.000.000 de registros creados desde una base de datos Oracle.
Erdem KAYA
8
df = DataFrame(cursor.fetchall())devuelve ValueError: DataFrame constructor not properly called!, parece que la tupla de tuplas no es aceptable para el constructor DataFrame. Tampoco hay .keys()un cursor en el modo diccionario o tupla.
Mobigital
3
Solo tenga en cuenta que el método de claves solo funcionará con los resultados obtenidos usando sqlalchemy. Pyodbc usa el atributo de descripción para las columnas.
Filip
¿Puede esto funcionar para las bases de datos de Postgres? Estoy tratando de obtener nombres de columna para el marco de datos de resultado con la keys()función, pero no puedo hacer que funcione.
Bowen Liu
1
@BowenLiu Sí, se puede usar con psycopg2df.columns=[ x.name for x in recoverall.description ]
Gnudiff
137

Edición: marzo de 2015

Como se indica a continuación, pandas ahora usa SQLAlchemy para leer desde ( read_sql ) e insertar en ( to_sql ) una base de datos. Lo siguiente debería funcionar

import pandas as pd

df = pd.read_sql(sql, cnxn)

Respuesta anterior: Via mikebmassey de una pregunta similar

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()
beardc
fuente
Esta parece ser la mejor manera de hacerlo, ya que no necesita usar manualmente .keys () para obtener el índice de la columna. Probablemente la respuesta de Daniel fue escrita antes de que existiera este método. También puede usar pandas.io.sql.read_frame ()
RobinL
1
@openwonk, ¿dónde se implementaría pd.read_sql()en el fragmento de código anterior?
3kstc
De hecho, desde mi última respuesta, he usado pyodbcy pandasjuntos bastante. Añadiendo una nueva respuesta con el ejemplo, FYI.
openwonk
33

Si está utilizando el ORM de SQLAlchemy en lugar del lenguaje de expresión, es posible que desee convertir un objeto de tipo sqlalchemy.orm.query.Queryen un marco de datos de Pandas.

El enfoque más limpio es obtener el SQL generado a partir del atributo de declaración de la consulta y luego ejecutarlo con el read_sql()método de pandas . Por ejemplo, comenzando con un objeto de consulta llamado query:

df = pd.read_sql(query.statement, query.session.bind)
Nathan Gould
fuente
5
Un enfoque más eficiente es obtener la declaración de sqlalchemy y dejar que los pandas hagan la consulta por sí mismos pandas.read_sql_query, pasándola query.statement. Vea esta respuesta: stackoverflow.com/a/29528804/1273938
LeoRochael
¡Gracias @LeoRochael! Edité mi respuesta. ¡Definitivamente más limpio!
Nathan Gould
23

Editar 2014-09-30:

pandas ahora tiene una read_sqlfunción. Definitivamente quieres usar eso en su lugar.

Respuesta original:

No puedo ayudarte con SQLAlchemy: siempre uso pyodbc, MySQLdb o psychopg2 según sea necesario. Pero al hacerlo, una función tan simple como la siguiente tiende a adaptarse a mis necesidades:

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
fuente
Creo que necesitas importar decimal en algún lugar arriba.
joe desde el
@joefromct Quizás, pero esta respuesta es tan obsoleta que realmente debería golpear todo y mostrar los métodos de los pandas.
Paul H
Puede ser relevante para algunos ... la razón por la que estaba estudiando esto fue por mi otro problema, usando read_sql () aquí stackoverflow.com/questions/32847246/…
joefromct
Es relevante para aquellos que no pueden usar SQLAlchemy, que no es compatible con todas las bases de datos.
lamecicle
@lamecicle algo en desacuerdo. IIRC, read_sqltodavía puede aceptar conexiones que no sean de SQLAlchemy a través de, por ejemplo, pyodbc, psychopg2, etc.
Paul H
16

Conector MySQL

Para aquellos que funcionan con el conector mysql, pueden usar este código como punto de partida. (Gracias a @Daniel Velkov)

Refs usados:


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
fuente
9

Aquí está el código que utilizo. Espero que esto ayude.

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
fuente
9

Esta es una respuesta breve y clara a su 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)
DeshDeep Singh
fuente
9

1. Usando 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. Usando 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
fuente
respuesta simple y genial!
Lucas Aimaretto
5

Como Nathan, a menudo quiero volcar los resultados de una consulta sqlalchemy o sqlsoup en un marco de datos de Pandas. Mi propia solución para esto es:

query = session.query(tbl.Field1, tbl.Field2)
DataFrame(query.all(), columns=[column['name'] for column in query.column_descriptions])
Janak Mayer
fuente
1
Si tiene un objeto de consulta. Es más eficiente obtener la declaración de sqlalchemy y dejar que los pandas hagan la consulta por sí mismos pandas.read_sql_query, pasándola query.statement. Vea esta respuesta: stackoverflow.com/a/29528804/1273938
LeoRochael
4

resoveralles un objeto ResultProxy sqlalchemy. Puede leer más sobre esto en los documentos de sqlalchemy , este último explica el uso básico de trabajar con motores y conexiones. Importante aquí es queresoverall es como un dict.

A los pandas le gustan los objetos similares a dict para crear sus estructuras de datos, consulte los documentos en línea

Buena suerte con sqlalchemy y pandas.

Wouter Overmeire
fuente
4

Simplemente use pandasy pyodbcjuntos. Tendrá que modificar su cadena de conexión ( connstr) de acuerdo con las especificaciones de su base de datos.

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

Lo he usado pyodbccon varias bases de datos empresariales (por ejemplo, SQL Server, MySQL, MariaDB, IBM).

openwonk
fuente
¿Cómo escribir este marco de datos nuevamente en MSSQL usando Pyodbc? Más que usar sqlalchemy
Ramsey
Usa el to_sqlmétodo en el DataFrameobjeto. Ese método está predeterminado en SQLite, por lo que debe pasarle explícitamente un objeto que apunte a la base de datos MSSQL. Ver documentos .
openwonk
Probé el de abajo y tengo alrededor de 200K filas con 13 columnas. Tampoco se completa después de 15 minutos. ¿Algunas ideas? df.to_sql ('tablename', engine, schema = 'schemaname', if_exists = 'append', index = False)
Ramsey
Eso parece lento ... probablemente necesitaría ver todo el código en acción, lo siento. Ojalá pandasestuviera más optimizado para el trabajo ETL ligero, pero por desgracia ...
openwonk
3

Esta pregunta es vieja, pero quería agregar mis dos centavos. Leí la pregunta como "Quiero ejecutar una consulta en mi [mi] base de datos SQL y almacenar los datos devueltos como estructura de datos Pandas [DataFrame]".

Por el código, parece que te refieres a la base de datos mysql y asumes que te refieres a pandas 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)

Por ejemplo,

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

Esto importará todas las filas de testTable en un DataFrame.

BubbleGuppies
fuente
1

Aquí esta el mio. Por si acaso si está utilizando "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
Kennyut
fuente
1

pandas.io.sql.write_frame está ANULADO. https://pandas.pydata.org/pandas-docs/version/0.15.2/generated/pandas.io.sql.write_frame.html

Debería cambiar para usar pandas.DataFrame.to_sql https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

Hay otra solucion. PYODBC a Pandas - DataFrame no funciona - La forma de los valores pasados ​​es (x, y), los índices implican (w, z)

A partir de Pandas 0.12 (creo) puedes hacer:

import pandas
import pyodbc

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

data = pandas.read_sql(sql, cnn)

Antes de 0.12, podía hacer:

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

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

data = read_frame(sql, cnn)
江明哲
fuente
Esta es, con mucho, la forma más fácil
Wilmer E. Henao
0

Mucho tiempo desde la última publicación, pero tal vez ayude a alguien ...

Camino más corto que Paul H:

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

la mejor manera de hacer esto

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

Si el tipo de resultado es ResultSet , primero debe convertirlo a diccionario. Luego, las columnas de DataFrame se recopilarán automáticamente.

Esto funciona en mi caso:

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