การแปลง SQLAlchemy ORM เป็น DataFrame แพนด้า


109

หัวข้อนี้ไม่ได้รับการแก้ไขมาสักระยะหนึ่งแล้วที่นี่หรือที่อื่น ๆ มีวิธีแก้ปัญหาในการแปลง SQLAlchemy <Query object>เป็น DataFrame แพนด้าหรือไม่?

Pandas มีความสามารถในการใช้งานpandas.read_sqlแต่ต้องใช้ Raw SQL ฉันมีเหตุผลสองประการที่ต้องการหลีกเลี่ยง: 1) ฉันมีทุกอย่างแล้วโดยใช้ ORM (เหตุผลที่ดีในตัวของมันเอง) และ 2) ฉันใช้รายการไพ ธ อนเป็นส่วนหนึ่งของแบบสอบถาม (เช่นคลาสโมเดลของฉันอยู่.db.session.query(Item).filter(Item.symbol.in_(add_symbols)ที่ไหนItemและadd_symbolsเป็นรายการ). SELECT ... from ... WHERE ... INนี่คือเทียบเท่าของ SQL

เป็นไปได้หรือไม่

คำตอบ:


194

ด้านล่างนี้ควรใช้งานได้ในกรณีส่วนใหญ่:

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

ดูpandas.read_sqlเอกสารประกอบสำหรับข้อมูลเพิ่มเติมเกี่ยวกับพารามิเตอร์


@van +1 แต่สามารถทำได้ด้วยรายละเอียดเล็กน้อย เช่นฉันทำdf = pd.read_sql(query, query.bind)เมื่อqueryเป็นไฟล์sqlalchemy.sql.selectable.Select. 'Select' object has no attribute 'session'มิฉะนั้นผมได้
Little Bobby Tables

เพื่อที่จะคัดลอกวางฉันเพิ่มเชื่อมโยงไปยังเอกสารโดยตรงในคำตอบซึ่งครอบคลุมคำถามของคุณ: คุณควรให้conพารามิเตอร์ซึ่งสามารถเป็นengineหรือconnection string
รถตู้

@van จะดีกว่าไหมถ้าใช้ query.session.connection () ที่นี่ มิฉะนั้นแบบสอบถามจะไม่คำนึงถึงการเปลี่ยนแปลงที่ไม่เป็นไปตามรายการในเซสชัน ...
ข้อมูล

1
@dataflow: ฉันคิดว่าคุณพูดถูก แต่ฉันไม่เคยทดสอบสมมติฐาน
รถตู้

@van - สิ่งนี้พ่น 'TypeError: รายการลำดับ 0: สตริงที่คาดไว้, DefaultMeta found'; ฉีกผมทั้งวันพยายามคิดว่ามีอะไรผิดปกติ สิ่งเดียวที่ฉันคิดได้ก็คือมันอาจเกี่ยวข้องกับการพยายามดึงการเชื่อมต่อออกจาก scoped_session ....
andrewpederson

89

เพื่อให้ชัดเจนยิ่งขึ้นสำหรับโปรแกรมเมอร์มือใหม่ของแพนด้านี่คือตัวอย่างที่เป็นรูปธรรม

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

ที่นี่เราเลือกการร้องเรียนจากตารางการร้องเรียน (แบบจำลอง sqlalchemy คือการร้องเรียน) ด้วย id = 2


1
ฉันคิดว่านี่ชัดเจนมากขึ้นเมื่อรหัสเป็นตาม ORM
user40780

พระเจ้าช่วย! ฉันต่อสู้กับ sqlAlchemy นรกมาก หมายเหตุด้านข้าง: คุณสามารถเขียน read_sql ('SELECT * FROM TABLENAME', db.session.bind) ขอบคุณ. คำตอบข้างต้นช่วยฉันได้มากกว่าคำตอบที่ยอมรับ
PallavBakshi

3
อะไร.statementทำอย่างไร
กระวาน

4
@cardamom จะส่งคืนแบบสอบถาม sql
Nuno André

10

โซลูชันที่เลือกใช้ไม่ได้ผลสำหรับฉันเนื่องจากฉันได้รับข้อผิดพลาดอยู่เรื่อย ๆ

AttributeError: วัตถุ 'AnnotatedSelect' ไม่มีแอตทริบิวต์ 'ต่ำกว่า'

ฉันพบว่าสิ่งต่อไปนี้ใช้งานได้:

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

4

หากคุณต้องการรวบรวมคำค้นหาที่มีพารามิเตอร์และอาร์กิวเมนต์เฉพาะภาษาให้ใช้สิ่งนี้:

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)

การนำเข้าselectในdf_query = select([DailyTrendsTable])จะหายไป from sqlalchemy import select
Carlos Azevedo

0

เพื่อความสมบูรณ์: นอกจากฟังก์ชัน Pandas read_sql_query()คุณยังสามารถใช้ฟังก์ชัน Pandas-DataFrame from_records()เพื่อแปลงไฟล์structured or record ndarray to DataFrame.
สิ่งนี้มีประโยชน์หากคุณได้ดำเนินการค้นหาใน SQLAlchemy แล้วและมีผลลัพธ์ที่พร้อมใช้งานแล้ว:

import pandas as pd 
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker


SQLALCHEMY_DATABASE_URI = 'postgresql://postgres:postgres@localhost:5432/my_database'
engine = create_engine(SQLALCHEMY_DATABASE_URI, pool_pre_ping=True, echo=False)
db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base(bind=engine)


class Currency(Base):
    """The `Currency`-table"""
    __tablename__ = "currency"
    __table_args__ = {"schema": "data"}

    id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String(64), nullable=False)


# Defining the SQLAlchemy-query
currency_query = db.query(Currency).with_entities(Currency.id, Currency.name)

# Getting all the entries via SQLAlchemy
currencies = currency_query.all()

# We provide also the (alternate) column names and set the index here,
# renaming the column `id` to `currency__id`
df_from_records = pd.DataFrame.from_records(currencies
    , index='currency__id'
    , columns=['currency__id', 'name'])
print(df_from_records.head(5))

# Or getting the entries via Pandas instead of SQLAlchemy using the
# aforementioned function `read_sql_query()`. We can set the index-columns here as well
df_from_query = pd.read_sql_query(currency_query.statement, db.bind, index_col='id')
# Renaming the index-column(s) from `id` to `currency__id` needs another statement
df_from_query.index.rename(name='currency__id', inplace=True)
print(df_from_query.head(5))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.