SQLAlchemy Konwersja ORM do pandy DataFrame

107

Ten temat nie był poruszany od jakiegoś czasu, tutaj ani gdzie indziej. Czy istnieje rozwiązanie konwertujące SQLAlchemy <Query object>na pandas DataFrame?

Pandy mają możliwość używania, pandas.read_sqlale wymaga to użycia surowego SQL. Mam dwa powody, dla których chcę tego uniknąć: 1) mam już wszystko przy użyciu ORM (dobry powód sam w sobie) i 2) używam list Pythona jako części zapytania (np .: .db.session.query(Item).filter(Item.symbol.in_(add_symbols)gdzie Itemjest moja klasa modelu i add_symbolsjest listą). To jest odpowiednik SQL SELECT ... from ... WHERE ... IN.

Czy coś jest możliwe?

Jared
źródło

Odpowiedzi:

192

Poniżej powinno działać w większości przypadków:

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

pandas.read_sqlWięcej informacji na temat parametrów można znaleźć w dokumentacji.

awangarda
źródło
@van +1, ale przydałoby się trochę więcej szczegółów. np. zrobiłem, df = pd.read_sql(query, query.bind)gdy queryjest sqlalchemy.sql.selectable.Select. W przeciwnym razie mam 'Select' object has no attribute 'session'.
Stoły Little Bobby
W celu kopiowania-wklejania dodałem link do dokumentacji bezpośrednio w odpowiedzi, która obejmuje Twoje pytanie: należy podać conparametr, którym może być enginelubconnection string
van
@van Czy lepiej byłoby użyć tutaj zapytania.session.connection ()? W przeciwnym razie zapytanie nie uwzględni niepohamowanych zmian w sesji ...
dataflow
1
@dataflow: Myślę, że masz rację, ale nigdy nie testowałem tego założenia.
van
@van - wyrzuca 'TypeError: sequence item 0: spodziewany ciąg, DefaultMeta found'; wyrywam sobie włosy przez cały dzień, próbując dowiedzieć się, co jest nie tak. Jedyne, co mogę sobie wyobrazić, to to, że może to mieć coś wspólnego z próbą wyodrębnienia połączenia z sesji scoped_session ....
andrewpederson
86

Aby było to bardziej zrozumiałe dla początkujących programistów pand, oto konkretny przykład:

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

Tutaj wybieramy reklamację z tabeli reklamacji (model sqlalchemy to Reklamacja) o id = 2

Chandan Purohit
źródło
1
Myślę, że jest to bardziej jasne, gdy kod jest oparty na ORM.
user40780
O MÓJ BOŻE! Dużo walczyłem z sqlAlchemy hell. Na marginesie: możesz także napisać read_sql ('SELECT * FROM TABLENAME', db.session.bind). Dzięki. Powyższa odpowiedź pomogła mi bardziej niż zaakceptowana.
PallavBakshi
3
Co robi .statement?
kardamon,
4
@cardamom zwraca zapytanie sql.
Nuno André
10

Wybrane rozwiązanie nie zadziałało, ponieważ ciągle otrzymywałem błąd

AttributeError: Obiekt „AnnotatedSelect” nie ma atrybutu „niższy”

Okazało się, że działa:

df = pd.read_sql_query(query.statement, engine)
jorr45
źródło
4

Jeśli chcesz skompilować zapytanie z parametrami i argumentami specyficznymi dla dialektu, użyj czegoś takiego:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)
Johan Dahlin
źródło
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
źródło
Brak importu selectw df_query = select([DailyTrendsTable]). from sqlalchemy import select
Carlos Azevedo