【问题标题】:INSERT INTO SELECT based on a dataframe基于数据框的 INSERT INTO SELECT
【发布时间】:2020-04-19 16:11:48
【问题描述】:

我有一个数据框 df,我想执行一个查询以将数据框中的所有值插入到表中。基本上我试图加载为以下查询:

INSERT INTO mytable
SELECT *
FROM mydataframe

为此,我有以下代码:

import pyodbc
import pandas as pd

connection = pyodbc.connect('Driver={' + driver + '} ;'
                            'Server=' + server + ';'
                            'UID=' + user + ';'
                            'PWD=' + pass + ';')

cursor = connection.cursor()

query = 'SELECT * FROM [myDB].[dbo].[myTable]'
df = pd.read_sql_query(query, connection)

sql = 'INSERT INTO [dbo].[new_date] SELECT * FROM :x'
cursor.execute(sql, x=df)
connection.commit()

但是,我收到以下错误:

TypeError: execute() takes no keyword arguments

有谁知道我做错了什么?

【问题讨论】:

  • 为什么不使用read_sql 的对应项和to_sql?不要注意后者需要 SQLAlchemy 连接(而不是像 pyodbc 这样的原始 DB-API 连接)。
  • 我试过了,但是我发现了很多问题,比如“找不到数据源名称并且没有指定默认驱动程序 (0) (SQLDriverConnect)”)'
  • 有关连接设置,请参阅 MS SQL Server 的 SQLAlchemy 文档:docs.sqlalchemy.org/en/13/dialects/…

标签: python sql-server pandas pyodbc


【解决方案1】:

我在将 pandas 与 SQL Server 连接时也遇到了一些问题。但我有这个解决方案来编写我的 df:

import pyodbc
import sqlalchemy

engine = sqlalchemy.create_engine('mssql+pyodbc://{0}:{1}@{2}:{3}/{4}?driver={5}'.format(username,password,server,port,bdName,driver))
pd.to_sql("TableName",con=engine,if_exists="append")

【讨论】:

  • 我真的认为使用 pandas to_sql() 比使用 SQL INSERTstatement 更好!
  • 我已经尝试过了,但我发现了很多问题,例如“未找到数据源名称并且未指定默认驱动程序 (0) (SQLDriverConnect)”)。我正在输入驱动程序名称“SQL Server”
  • 我们看不到您的驱动程序,因此您必须进行相应调整。请参阅docs,其中空格必须替换为+。也许:...driver=ODBC+{5}.format(..., driver.replace(' ', '+')。在动态变量之前使用硬编码值进行测试。
  • 是的,@Parfait 有道理。但我会将我的问题编辑为通用驱动程序
【解决方案2】:

请参阅下面我最喜欢的解决方案,其中包含 UPSERT 语句。

df_columns = list(df)
columns = ','.join(df_columns)
values = 'VALUES({})'.format(','.join(['%s' for col in df_columns]))
update_list = ['{} = EXCLUDED.{}'.format(col, col) for col in df_columns]
update_str = ','.join(update_list)
insert_stmt = "INSERT INTO {} ({}) {} ON CONFLICT ([your_pkey_here]) DO UPDATE SET {}".format(table, columns, values, update_str)

【讨论】:

    【解决方案3】:

    cursor.execute 不接受关键字参数。进行插入的一种方法是使用以下代码 sn-p。

    cols = "`,`".join([str(i) for i in df.columns.tolist()])
    
    # Insert DataFrame recrds one by one.
    for i,row in df.iterrows():
        sql = "INSERT INTO `[dbo].[new_date]` (`" +cols + "`) VALUES (" + "?,"*(len(row)-1) + "%s)"
        cursor.execute(sql, tuple(row))
    

    在这里,您正在遍历每一行,然后将其插入到表中。

    【讨论】:

      【解决方案4】:

      对于来自 Pandas 的原始 DB-API 插入查询,请考虑 DataFrame.to_numpy()executemany 并避免任何顶层 for 循环。但是,在追加查询中必须使用显式列。调整下面的列和 qmark 参数占位符以对应数据框列。

      # PREPARED STATEMENT
      sql = '''INSERT INTO [dbo].[new_date] (Col1, Col2, Col3, ...)
               VALUES (?, ?, ?, ...)
            '''
      
      #  EXECUTE PARAMETERIZED QUERY
      cursor.executemany(sql, df.to_numpy().tolist())   
      conn.commit()
      

      (顺便说一句,在 SQL 查询中,最好的做法是始终显式引用列并避免 SELECT * 以提高代码的可读性、可维护性甚至性能。)

      【讨论】:

        【解决方案5】:

        感谢您的回答 :) 但我使用以下代码来解决我的问题:

        params = urllib.parse.quote_plus("DRIVER={SQL Server};SERVER=servername;DATABASE=database;UID=user;PWD=pass")
        engine = sqlalchemy.create_engine("mssql+pyodbc:///?odbc_connect=%s" % params)
        engine.connect()
        query = query
        df = pd.read_sql_query(query, connection)
        df.to_sql(name='new_table',con=engine, index=False, if_exists='append')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-03
          • 2015-11-05
          • 2012-01-23
          • 2023-02-09
          • 2014-03-22
          • 1970-01-01
          • 1970-01-01
          • 2012-08-22
          相关资源
          最近更新 更多