Conversion de SQLAlchemy ORM en pandas DataFrame

107

Ce sujet n'a pas été abordé depuis un moment, ici ou ailleurs. Existe-t-il une solution pour convertir un SQLAlchemy <Query object>en un pandas DataFrame?

Pandas a la capacité d'utiliser pandas.read_sqlmais cela nécessite l'utilisation de SQL brut. J'ai deux raisons de vouloir l'éviter: 1) J'ai déjà tout utilisant l'ORM (une bonne raison en soi) et 2) J'utilise des listes python dans le cadre de la requête (par exemple: .db.session.query(Item).filter(Item.symbol.in_(add_symbols)Itemest ma classe de modèle et add_symbolsest une liste). C'est l'équivalent de SQL SELECT ... from ... WHERE ... IN.

Est-ce que quelque chose est possible?

Jared
la source

Réponses:

192

Ci-dessous devrait fonctionner dans la plupart des cas:

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

Consultez la pandas.read_sqldocumentation pour plus d'informations sur les paramètres.

van
la source
@van +1 mais pourrait faire avec un peu plus de détails. par exemple je l'ai fait df = pd.read_sql(query, query.bind)quand queryest un sqlalchemy.sql.selectable.Select. Sinon, je l'ai 'Select' object has no attribute 'session'.
Little Bobby Tables
Afin de copier-coller, j'ai ajouté un lien vers la documentation directement dans la réponse, qui couvre votre question: vous devez fournir le conparamètre, qui peut être le engineouconnection string
van
@van Serait-il préférable d'utiliser ici query.session.connection ()? Sinon, la requête ne prend pas en compte les changements non persistants dans la session ...
dataflow
1
@dataflow: Je pense que vous avez raison, mais je n'ai jamais testé l'hypothèse.
van
@van - cela lance 'TypeError: élément de séquence 0: chaîne attendue, DefaultMeta trouvée'; Je me suis arraché les cheveux toute la journée pour essayer de comprendre ce qui ne va pas La seule chose que je peux comprendre, c'est que cela pourrait avoir quelque chose à voir avec la tentative d'extraire une connexion d'une scoped_session ....
andrewpederson
86

Juste pour rendre cela plus clair pour les programmeurs pandas novices, voici un exemple concret,

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

Ici, nous sélectionnons une plainte dans la table des plaintes (le modèle sqlalchemy est une plainte) avec id = 2

Chandan Purohit
la source
1
Je pense que c'est plus clair, lorsque le code est basé sur ORM.
user40780
OMG! J'ai beaucoup lutté avec sqlAlchemy hell. Juste un petit mot ici: vous pouvez également écrire read_sql ('SELECT * FROM TABLENAME', db.session.bind). Merci. La réponse ci-dessus m'a aidé plus que la réponse acceptée.
PallavBakshi
3
Que fait .statement-on?
cardamome
4
@cardamom il renvoie la requête SQL.
Nuno André
10

La solution sélectionnée n'a pas fonctionné pour moi, car je continuais à recevoir l'erreur

AttributeError: l'objet 'AnnotatedSelect' n'a pas d'attribut 'lower'

J'ai trouvé ce qui suit fonctionné:

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

Si vous souhaitez compiler une requête avec des paramètres et des arguments spécifiques au dialecte, utilisez quelque chose comme ceci:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)
Johan Dahlin
la source
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
la source
L'importation de selectin df_query = select([DailyTrendsTable])est manquante. from sqlalchemy import select
Carlos Azevedo