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?

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.


@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


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)

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)

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)

Falta la importación de selectin df_query = select([DailyTrendsTable]). from sqlalchemy import select
Carlos Azevedo
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.