【问题标题】:Insert Data to SQL Server Table using pymssql使用 pymssql 将数据插入 SQL Server 表
【发布时间】:2018-06-04 09:42:07
【问题描述】:

我正在尝试将数据框写入 SQL Server 表。我的代码:

conn = pymssql.connect(host="Dev02", database="DEVDb")
cur = conn.cursor()
query = "INSERT INTO dbo.SCORE_TABLE VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
cur.executemany(query, df_sql)
conn.commit()
cur.close()
conn.close()

df_sql 的维度是(5860, 20),即数据框中的列数与 SQL Server 表中的列数相同。我仍然收到以下错误:

ValueError:sql 中的占位符比可用的参数多

以下更新

根据其中一位 cmets,我尝试使用 turbodbc,如下所示:

conn = turbodbc.connect(driver="{SQL Server}", server="Dev02", Database="DEVDb")
conn.use_async_io = True
cur = conn.cursor()
query = "INSERT INTO dbo.STG_CONTACTABILITY_SCORE VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
cur.executemany(query, df_sql.values)
cur.commit()
cur.close()
conn.close()

我收到以下错误:

ValueError:具有多个元素的数组的真值是 模糊的。使用 a.any() 或 a.all()

我不明白。这里有什么问题。我看到df_sql.values 并没有发现任何问题。

ndarray的第一行如下:

[nan 'DUSTIN HOPKINS' 'SOUTHEAST MISSOURI STATE UNIVERSITY' 13.0
  '5736512217' None None 'Monday' '8:00AM' '9:00AM' 'Summer' None None None
  None '2017-12-22 10:39:30.626331' 'Completed' None '1-11KUFFZ'
  'Central Time Zone']

【问题讨论】:

标签: python sql-server pandas pymssql


【解决方案1】:

我想你只需要指定每个列名,不要忘记表必须有id字段来收取数据框索引:

conn = pymssql.connect(host="Dev02", database="DEVDb")
cur = conn.cursor()
query = """INSERT INTO dbo.SCORE_TABLE(index, column1, column2, ..., column20)
            VALUES (?, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 
            %s, %s, %s, %s, %s, %s)"""
cur.executemany(query, df_sql)
conn.commit()
cur.close()
conn.close()

好的,我一直在使用 pandas,我将最后一个数据帧导出到 csv,如下所示:

df.to_csv('new_file_name.csv', sep=',', encoding='utf-8')

然后我只使用了pyobdcBULK INSERT Transact-SQL 之类的:

import pyodbc

conn = pyodbc.connect(DRIVER='{SQL Server}', Server='server_name', Database='Database_name', trusted_connection='yes')
cur = conn.cursor()

cur.execute("""BULK INSERT table_name
               FROM 'C:\\Users\\folders path\\new_file_name.csv'
               WITH
               (
                   CODEPAGE = 'ACP',
                   FIRSTROW = 2,
                   FIELDTERMINATOR = ',',
                   ROWTERMINATOR = '\n'
               )""")
conn.commit()

cur.close()
conn.close()

将 15314 行记入 SQL Server 只需一秒钟。我希望这能给你一个想法。

【讨论】:

  • 感谢@virtualdvid 的帮助,很抱歉迟到了。这行得通。
  • @virtualvid:我正在尝试将您的 BULK INSERT 建议用于我的一个项目,但我不断收到 **Operating system could not locate the path" of new_file_name.csv。文件在路径中我正在指定。你能想到可能是什么问题吗?
  • @KrishnangKDalal 你能告诉我你正在使用的线路吗?
  • 如果数据必须进入模式“myschema”而不是进入“dbo”,这会是什么样子?我所有的表都有一个前缀 'ms_' 但我希望它们是 'myschema.'ms_'.. 但是,如果我将 'ms_' 替换为 'myschema.ms_' 所有表看起来像这样: 'dbo.myschema.ms_' ...
【解决方案2】:

如果我理解正确你想使用DataFrame.to_sql() 方法:

df_sql.to_sql('dbo.SCORE_TABLE', conn, index=False, if_exists='append')

【讨论】:

  • 是的,我知道这一点,但我读到 pandas to_sql 对于大量数据来说比 pymssql 慢。您认为在处理大量数据时,两种方法之间是否存在主要的性能差异?大量,我的意思是大约 80k 到 100k 行和 20 列
  • @KrishnangKDalal,考虑使用turbodbc
  • 查看更新后的问题。 turbodbc 确实是一个不错的软件包,但我仍然遇到错误。
  • @KrishnangKDalal ...您是否真的尝试过to_sql 方法并测试自己,甚至使用SQLAlchemy 引擎而不是原始连接?您所听到的可能并不总是真实的!
  • @Parfait:是的,我已经测试了to_sql,插入 26646 行只需要 7 分钟多一点。我想比较其他方法,但为此,我必须让其他方法起作用。
【解决方案3】:

可能executemany 将来自您的df.values 调用的ndarray 中的每一行视为一个 项,因为值之间没有逗号分隔符。因此,占位符的数量超过了实际绑定的值,您会收到不匹配错误。

考虑将数组转换为元组元组(或列表列表/列表元组/元组列表),然后将该对象传递给executemany

query = "INTO dbo.SCORE_TABLE VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"    
sql_data = tuple(map(tuple, df.values))

cur.executemany(query, sql_data)
cur.commit()

【讨论】:

  • 不,我尝试将数组转换为元组的元组和列表列表,但得到turbodbc.exceptions.DatabaseError: Invalid number of parameters (expected 0, got 20) 错误
  • 这适用于 pymssql,因为占位符不同。在 turbodbc 中尝试使用 ?
  • 我认为它正在工作,但我的 IT 团队添加了一个标识列,由于权限问题,我无法通过关闭 IDENTITY_INSERT 来插入任何值,并且我无法在不提供任何信息的情况下继续该列的值。一旦我把它整理出来,我会接受答案。谢谢
  • 如果标识字段与数据框中的列同名,则将该列放入 pandas 并删除一个占位符,然后重试。标识列是数据库引擎自动插入新行而不是用户的自动编号字段。
  • 是的,我试过了,但我收到了这个错误:turbodbc.exceptions.DatabaseError: ODBC error state: IM002 native error code: 0 message: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified。我的数据库中肯定有该表,因为我可以使用 to_sql 插入数据
【解决方案4】:

这对我有用-

insert_query = """INSERT INTO dbo.temptable(CHECK_TIME, DEVICE, METRIC, VALUE, TOWER, LOCATION, ANOMALY, ANOMALY_SCORE, ANOMALY_SEVERITY)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"""
write_data = tuple(map(tuple, data_frame.values))
cursor.executemany(insert_query, write_data)
con.commit()
cursor.close()
con.close()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    相关资源
    最近更新 更多