【问题标题】:Using Pandas Dataframe within a SQL Join在 SQL 连接中使用 Pandas 数据框
【发布时间】:2019-06-05 23:34:08
【问题描述】:

我正在尝试使用我在 Postgres 数据库中的外部表对数据框的内容执行 SQL 连接。

这是 Dataframe 的样子:

>>> df
   name  author  count
0  a     b       10
1  c     d       5
2  e     f       2

我需要使用如下所示的 Postgres 表加入它:

TABLE: blog
title   author    url    
a       b         w.com
b       b         x.com
e       g         y.com

这是我正在尝试做的,但这似乎不是查询的正确语法:

>>> sql_join = r"""select b.*, frame.*  from ({0}) frame
        join blog b
        on frame.name = b.title
        where frame.owner = b.owner 
        order by frame.count desc
        limit 30;""".format(df)

>>> res = pd.read_sql(sql_join, connection)

我不确定如何在 sql 查询中使用数据框中的值。 有人可以指出我正确的方向吗?谢谢!

编辑:根据我的用例,在给定内存和性能限制的情况下,我无法将博客表转换为数据帧。

【问题讨论】:

    标签: python sql postgresql pandas


    【解决方案1】:

    我设法做到了这一点,而无需将数据帧转换为临时表,也无需将 SQL 从博客表中读取到数据帧中。

    对于面临同样问题的其他人,这是使用各种虚拟表来实现的。

    这是我最终的 sql 查询的样子:

    >>> inner_string = "VALUES ('a','b',10), ('c','d',5), ('e','f',2)"
    
    >>> sql_join = r"""SELECT * FROM blog
            JOIN ({0}) AS frame(title, owner, count)
            ON blog.title = frame.title
            WHERE blog.owner = frame.owner 
            ORDER BY frame.count DESC
            LIMIT 30;""".format(inner_string)
    
    >>> res = pd.read_sql(sql_join, connection)
    

    您可以使用字符串操作将数据框中的所有行转换为一个类似于inner_string 的大字符串。

    【讨论】:

      【解决方案2】:

      您应该从 Postgres 表中创建另一个数据框,然后连接两个数据框。

      您可以使用read_sql 从表中创建一个df:

      import psycopg2  ## Python connector library to Postgres
      import pandas as pd
      
      conn = psycopg2.connect(...) ## Put your DB credentials here
      blog_df = pd.read_sql('blog', con=conn)
      ## This will bring `blog` table's data into blog_df
      

      应该是这样的:

      In [258]: blog_df
      Out[258]: 
        title author    url
      0     a      b  w.com
      1     b      b  x.com
      2     e      g  y.com
      

      现在,您可以使用merge 加入dfblog_df,如下所示:

      In [261]: pd.merge(df, blog_df, left_on='name', right_on='title')
      Out[261]: 
        name author_x  count title author_y    url
      0    a        b     10     a        b  w.com
      1    e        f      2     e        g  y.com
      

      你会得到如上的结果。您可以进一步清洁它。

      如果这有帮助,请告诉我。

      【讨论】:

      • 感谢您的回复 :) 合并数据帧是一种方法。不幸的是,将博客表带入是我试图避免做的事情。该表非常大,因此在我的用例中不是一个可行的解决方案。有其他方法吗?
      • @GenAsis - 然后以相反的方式执行:将数据帧推送到 Postgres 并在那里运行您的 JOIN。通过 SQLAlchemy 连接使用to_sql
      • @Parfait 我考虑过这一点,看来这可能是唯一的出路。我经常执行此操作,在理想情况下,我不想一直创建(临时)表来执行连接。这就是您将数据框推送到 postgres 的意思吗?
      • 您可以创建一次临时/临时表并根据需要定期清理/填充并加入最终表。这将是更有效的方式,因为您甚至可以为 Postgres 强大的查询引擎在暂存表和最终表之间的 join 字段设置索引!
      • 感谢@Parfait,我设法找到了一个适合我的干净解决方案(我在下面发布)!
      【解决方案3】:

      我也遇到过类似的问题。我找到了一种解决方法,它允许我加入两个不同的服务器,我只有只读权限。使用 sqlalchemy 插入 pandas 数据框,然后加入

      import sqlalchemy as sa
      import pandas as pd
      
      metadata = MetaData()
      sql_of_df = sa.Table(
          "##df",
          metadata,
          sa.Column("name", sa.String(x),   primary_key=True),
          sa.Column("author", sa.String(x), nullable=False),
          sa.Columnt("count", sa.Integer),
      )
      metadata.create_all(engine)
      dataframe_dict = df.to_dict(orient='records')
      insert_statement = sql_of_df.insert().values(
          {
              "name":sa.bindparam("name"),
              "author":sa.bindparam("author"),
              "count":sa.bindparam("count"),
         }
      )
      session.execute(insert_statement, dataframe_dict)
      
      statement=sa.text("SELECT * from blog Inner join ##df on blog.Title = ##df.name")
      session.execute(statement)
      
      

      【讨论】:

        猜你喜欢
        • 2017-09-11
        • 2021-07-25
        • 2022-07-11
        • 1970-01-01
        • 2020-03-14
        • 2021-10-09
        • 2018-05-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多