Conversione ORM di SQLAlchemy in DataFrame panda


107

Questo argomento non è stato affrontato da un po ', qui o altrove. Esiste una soluzione per convertire un SQLAlchemy <Query object>in un DataFrame panda?

Pandas ha la capacità di usare, pandas.read_sqlma questo richiede l'uso di SQL grezzo. Ho due motivi per volerlo evitare: 1) Ho già tutto usando l'ORM (una buona ragione in sé e per sé) e 2) Sto usando gli elenchi Python come parte della query (ad esempio: .db.session.query(Item).filter(Item.symbol.in_(add_symbols)dov'è la Itemmia classe del modello ed add_symbolsè un elenco). Questo è l'equivalente di SQL SELECT ... from ... WHERE ... IN.

È possibile qualcosa?

Risposte:


192

Di seguito dovrebbe funzionare nella maggior parte dei casi:

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

Vedere la pandas.read_sqldocumentazione per ulteriori informazioni sui parametri.


@ van +1 ma potrebbe fare con un po 'più di dettaglio. ad esempio, ho fatto df = pd.read_sql(query, query.bind)quando queryè un sqlalchemy.sql.selectable.Select. Altrimenti, ho 'Select' object has no attribute 'session'.
Little Bobby Tables

Per fare il copia-incolla, ho aggiunto il link alla documentazione direttamente nella risposta, che copre la tua domanda: dovresti fornire il conparametro, che può essere engineoconnection string
van

@van Sarebbe meglio usare query.session.connection () qui? Altrimenti la query non tiene conto delle modifiche non persistenti nella sessione ...
flusso di dati

1
@dataflow: penso che tu abbia ragione, ma non ho mai testato l'ipotesi.
van

@van - questo genera "TypeError: elemento sequenza 0: stringa prevista, DefaultMeta trovato"; Mi sto strappando i capelli tutto il giorno cercando di capire cosa c'è che non va. L'unica cosa che riesco a capire è che potrebbe avere qualcosa a che fare con il tentativo di estrarre una connessione da uno scoped_session ....
andrewpederson

86

Solo per rendere questo più chiaro per i programmatori panda alle prime armi, ecco un esempio concreto,

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

Qui selezioniamo un reclamo dalla tabella dei reclami (il modello sqlalchemy è Reclamo) con id = 2


1
Penso che questo sia più chiaro, quando il codice è basato su ORM.
user40780

OH MIO DIO! Ho lottato molto con sqlAlchemy hell. Solo una nota a margine qui: puoi anche scrivere read_sql ('SELECT * FROM TABLENAME', db.session.bind). Grazie. La risposta di cui sopra mi ha aiutato più di quella accettata.
PallavBakshi

3
Cosa fa .statement?
cardamomo

4
@cardamom restituisce la query sql.
Nuno André

10

La soluzione selezionata non ha funzionato per me, poiché continuavo a ricevere l'errore

AttributeError: l'oggetto "AnnotatedSelect" non ha attributo "inferiore"

Ho trovato funzionato quanto segue:

df = pd.read_sql_query(query.statement, engine)

4

Se vuoi compilare una query con parametri e argomenti specifici del dialetto, usa qualcosa del genere:

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)

Manca l' importazione di selectin df_query = select([DailyTrendsTable]). from sqlalchemy import select
Carlos Azevedo,
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.