【问题标题】:SQLAlchemy ORM conversion to pandas DataFrameSQLAlchemy ORM 转换为 pandas DataFrame
【发布时间】:2015-06-14 01:40:29
【问题描述】:

是否有将 SQLAlchemy <Query object> 转换为 pandas DataFrame 的解决方案?

Pandas 可以使用pandas.read_sql,但这需要使用原始 SQL。我想避免它有两个原因:

  1. 我已经拥有使用 ORM 的一切(这本身就是一个很好的理由)并且
  2. 我使用 python 列表作为查询的一部分,例如:

db.session.query(Item).filter(Item.symbol.in_(add_symbols) 其中Item 是我的模型类,add_symbols 是一个列表)。这相当于 SQL SELECT ... from ... WHERE ... IN

有什么可能吗?

【问题讨论】:

    标签: python pandas sqlalchemy flask-sqlalchemy


    【解决方案1】:

    如果使用 SQL 查询

    def generate_df_from_sqlquery(query):
       from pandas import DataFrame
       query = db.session.execute(query)
       df = DataFrame(query.fetchall())
       if len(df) > 0:
          df.columns = query.keys()
       else:
          columns = query.keys()
          df = pd.DataFrame(columns=columns)
    return df
    
    profile_df = generate_df_from_sqlquery(profile_query) 
    

    【讨论】:

      【解决方案2】:

      这个答案提供了一个使用 SQL Alchemy select 语句并返回熊猫数据框的可重现示例。它基于内存中的 SQLite 数据库,因此任何人都可以在不安装数据库引擎的情况下重现它。

      import pandas
      from sqlalchemy import create_engine
      from sqlalchemy import MetaData, Table, Column, Text
      from sqlalchemy.orm import Session
      

      定义表元数据并创建表

      engine = create_engine('sqlite://')
      meta = MetaData()
      meta.bind = engine
      user_table = Table('user', meta,
                         Column("name", Text),
                         Column("full_name", Text))
      user_table.create()
      

      Insert一些数据进入user

      stmt = user_table.insert().values(name='Bob', full_name='Sponge Bob')
      with Session(engine) as session:
          result = session.execute(stmt)
          session.commit()
      

      select 语句的结果读入pandas 数据框

      # Select data into a pandas data frame
      stmt = user_table.select().where(user_table.c.name == 'Bob')
      df = pandas.read_sql_query(stmt, engine)
      df
      Out:
        name   full_name
      0  Bob  Sponge Bob
      

      【讨论】:

      • 我使用它时收到错误:sqlalchemy.exc.ObjectNotExecutableError: Not an executable object:。你能帮帮我吗?
      • 你有最新版本的sqlalchemy和pandas吗?
      【解决方案3】:

      为了完整起见:作为 Pandas 函数 read_sql_query() 的替代方案,您还可以使用 Pandas 数据帧函数 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))
      

      【讨论】:

        【解决方案4】:
        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)
        

        【讨论】:

        • selectdf_query = select([DailyTrendsTable]) 中的导入丢失。 from sqlalchemy import select
        【解决方案5】:

        以下应该适用于大多数情况:

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

        有关参数的更多信息,请参阅pandas.read_sql 文档。

        【讨论】:

        • @van +1 但可以提供更多细节。例如当querysqlalchemy.sql.selectable.Select 时,我做了df = pd.read_sql(query, query.bind)。否则,我得到'Select' object has no attribute 'session'
        • 为了复制粘贴,我直接在答案中添加了指向文档的链接,这涵盖了您的问题:您应该提供con 参数,可以是engine 或@ 987654330@
        • @van 在这里使用 query.session.connection() 会更好吗?否则查询不会考虑会话中未持久的更改...
        • @dataflow:我认为你是对的,但我从未测试过这个假设。
        • @van - 这会抛出 'TypeError: sequence item 0: expected string, DefaultMeta found';一整天都在扯头发,试图找出问题所在。我唯一能想到的是,它可能与尝试从 scoped_session 中提取连接有关......
        【解决方案6】:

        选择的解决方案对我不起作用,因为我不断收到错误

        AttributeError: 'AnnotatedSelect' 对象没有属性 'lower'

        我发现以下方法有效:

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

        【讨论】:

          【解决方案7】:

          为了让新手 pandas 程序员更清楚,这里是一个具体的例子,

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

          这里我们从投诉表中选择一个投诉(sqlalchemy 模型是投诉),id = 2

          【讨论】:

          • 当代码是基于 ORM 时,我认为这更清楚。
          • 天啊!我在 sqlAlchemy 地狱中挣扎了很多。这里只是一个旁注:您也可以编写 read_sql('SELECT * FROM TABLENAME', db.session.bind) 。谢谢。上述答案对我的帮助超过了接受的答案。
          • .statement 是做什么的?
          • @cardamom 它返回 sql 查询。
          • 这为 SQLAlchemy 2.0 提供了NotImplementedError
          【解决方案8】:

          如果要编译带有参数和方言特定参数的查询,请使用以下内容:

          c = query.statement.compile(query.session.bind)
          df = pandas.read_sql(c.string, query.session.bind, params=c.params)
          

          【讨论】:

            猜你喜欢
            • 2020-07-29
            • 2023-01-20
            • 2015-10-28
            • 2014-10-05
            • 2017-03-17
            • 2017-03-23
            • 2014-06-26
            • 1970-01-01
            • 2017-04-13
            相关资源
            最近更新 更多