SQLAlchemy ORM conversão para pandas DataFrame

107

Este tópico não é abordado há algum tempo, aqui ou em outro lugar. Existe uma solução para converter um SQLAlchemy <Query object>em um DataFrame pandas?

O Pandas tem a capacidade de usar, pandas.read_sqlmas isso requer o uso de SQL bruto. Tenho dois motivos para querer evitá-lo: 1) Já tenho tudo usando o ORM (um bom motivo por si só) e 2) Estou usando listas Python como parte da consulta (por exemplo: .db.session.query(Item).filter(Item.symbol.in_(add_symbols)onde Itemestá minha classe de modelo e add_symbolsé uma lista). Isso é equivalente a SQL SELECT ... from ... WHERE ... IN.

É possível alguma coisa?

Jared
fonte

Respostas:

192

Abaixo deve funcionar na maioria dos casos:

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

Consulte a pandas.read_sqldocumentação para obter mais informações sobre os parâmetros.

furgão
fonte
@van +1, mas poderia ser preciso um pouco mais de detalhes. por exemplo, eu fiz df = pd.read_sql(query, query.bind)quando queryé a sqlalchemy.sql.selectable.Select. Caso contrário, eu consegui 'Select' object has no attribute 'session'.
Little Bobby Tables
Para copiar e colar, adicionei um link para a documentação diretamente na resposta, que aborda sua pergunta: você deve fornecer o conparâmetro, que pode ser o engineouconnection string
van
@van Seria melhor usar query.session.connection () aqui? Caso contrário, a consulta não leva em consideração mudanças não persistentes na sessão ...
fluxo de dados de
1
@dataflow: Acho que você está certo, mas nunca testei a suposição.
van
@van - lança 'TypeError: item de sequência 0: string esperada, DefaultMeta encontrado'; Tenho arrancado meu cabelo o dia todo tentando descobrir o que está errado. A única coisa que posso imaginar é que pode ter algo a ver com a tentativa de extrair uma conexão de uma scoped_session ....
andrewpederson
86

Só para deixar isso mais claro para programadores novatos de pandas, aqui está um exemplo concreto,

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

Aqui, selecionamos uma reclamação da tabela de reclamações (o modelo sqlalchemy é Reclamação) com id = 2

Chandan Purohit
fonte
1
Acho que fica mais claro quando o código é baseado em ORM.
user40780
AMD! Eu lutei muito com o inferno sqlAlchemy. Apenas uma observação lateral aqui: você também pode escrever read_sql ('SELECT * FROM TABLENAME', db.session.bind). Obrigado. A resposta acima me ajudou mais do que a aceita.
PallavBakshi
3
O que .statementfazer?
cardamomo de
4
@cardamom ele retorna a consulta sql.
Nuno André
10

A solução selecionada não funcionou para mim, pois continuava recebendo o erro

AttributeError: o objeto 'AnnotatedSelect' não tem atributo 'inferior'

Eu descobri que o seguinte funcionou:

df = pd.read_sql_query(query.statement, engine)
Jorr45
fonte
4

Se você deseja compilar uma consulta com parâmetros e argumentos específicos do dialeto, use algo assim:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)
Johan Dahlin
fonte
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
fonte
Falta a importação de selectin df_query = select([DailyTrendsTable]). from sqlalchemy import select
Carlos Azevedo