Conversión de SQLAlchemy ORM a pandas DataFrame

107

Este tema no se ha abordado en un tiempo, aquí o en otro lugar. ¿Existe una solución para convertir un SQLAlchemy <Query object>en un DataFrame de pandas?

Pandas tiene la capacidad de usar, pandas.read_sqlpero esto requiere el uso de SQL sin formato. Tengo dos razones para querer evitarlo: 1) Ya tengo todo usando el ORM (una buena razón en sí misma) y 2) Estoy usando listas de Python como parte de la consulta (por ejemplo: ¿ .db.session.query(Item).filter(Item.symbol.in_(add_symbols)dónde Itemestá mi clase modelo y add_symbolses una lista). Este es el equivalente de SQL SELECT ... from ... WHERE ... IN.

¿Es posible algo?

Jared
fuente

Respuestas:

192

A continuación debería funcionar en la mayoría de los casos:

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

Consulte la pandas.read_sqldocumentación para obtener más información sobre los parámetros.

camioneta
fuente
@van +1, pero le vendría bien un poco más de detalle. por ejemplo, lo hice df = pd.read_sql(query, query.bind)cuando queryes a sqlalchemy.sql.selectable.Select. De lo contrario, tengo 'Select' object has no attribute 'session'.
Little Bobby Tables
Para copiar y pegar, agregué un enlace a la documentación directamente en la respuesta, que cubre su pregunta: debe proporcionar el conparámetro, que puede ser engineoconnection string
van
@van ¿Sería mejor usar query.session.connection () aquí? De lo contrario, la consulta no tiene en cuenta los cambios no persistentes en la sesión ...
flujo de datos
1
@dataflow: Creo que tienes razón, pero nunca he probado la suposición.
furgoneta
@van: esto arroja 'TypeError: secuencia elemento 0: cadena esperada, DefaultMeta encontrado'; He estado arrancándome el pelo todo el día tratando de averiguar qué pasa. Lo único que puedo imaginar es que podría tener algo que ver con intentar extraer una conexión de una scoped_session ....
andrewpederson
85

Solo para que esto sea más claro para los programadores de pandas novatos, aquí hay un ejemplo concreto,

pd.read_sql(session.query(Complaint).filter(Complaint.id == 2).statement,session.bind) 

Aquí seleccionamos una queja de la tabla de quejas (el modelo de sqlalchemy es Queja) con id = 2

Chandan Purohit
fuente
1
Creo que esto es más claro cuando el código está basado en ORM.
user40780
¡DIOS MIO! Luché mucho con sqlAlchemy hell. Solo una nota al margen aquí: también puede escribir read_sql ('SELECT * FROM TABLENAME', db.session.bind). Gracias. La respuesta anterior me ayudó más que la aceptada.
PallavBakshi
3
¿Qué .statementhacer?
cardamomo
4
@cardamom devuelve la consulta sql.
Nuno André
10

La solución seleccionada no funcionó para mí, ya que seguía recibiendo el error

AttributeError: el objeto 'AnnotatedSelect' no tiene ningún atributo 'inferior'

Encontré lo siguiente funcionado:

df = pd.read_sql_query(query.statement, engine)
jorr45
fuente
4

Si desea compilar una consulta con parámetros y argumentos específicos de dialecto, use algo como esto:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)
Johan Dahlin
fuente
3
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('postgresql://postgres:postgres@localhost:5432/DB', echo=False)
Base = declarative_base(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()

conn = session.bind

class DailyTrendsTable(Base):

    __tablename__ = 'trends'
    __table_args__ = ({"schema": 'mf_analysis'})

    company_code = Column(DOUBLE_PRECISION, primary_key=True)
    rt_bullish_trending = Column(Integer)
    rt_bearish_trending = Column(Integer)
    rt_bullish_non_trending = Column(Integer)
    rt_bearish_non_trending = Column(Integer)
    gen_date = Column(Date, primary_key=True)

df_query = select([DailyTrendsTable])

df_data = pd.read_sql(rt_daily_query, con = conn)
Akshay Salvi
fuente
Falta la importación de selectin df_query = select([DailyTrendsTable]). from sqlalchemy import select
Carlos Azevedo