0

我的问题本质上是这样的:当我尝试将 to_sql 与 if_exists = 'append' 一起使用并且名称设置为我的 SQL Server 上已经存在的表时,python 崩溃了。

这是我的代码:

@event.listens_for(engine, 'before_cursor_execute') def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True

df.to_sql(name = 'existingSQLTable', con = engine, if_exists = 'append', index = False, chunksize = 10000, dtype = dataTypes)

我没有包括它,但 dataTypes 是所有列名及其数据类型的字典。

这是我得到的错误:

    Traceback (most recent call last):
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1116, in _execute_context
        context)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\default.py", line 447, in do_executemany
        cursor.executemany(statement, parameters)
    pyodbc.IntegrityError: ('23000', "[23000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Violation of PRIMARY KEY constraint 'PK__existingSQLTable__'. Cannot insert duplicate key in object 'dbo.existingSQLTable'. The duplicate key value is (20008.7, 2008-08-07, Fl). (2627) (SQLExecute); [23000] [Microsoft][SQL Server Native Client 11.0][SQL Server]The statement has been terminated. (3621)")

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last):
      File "<pyshell#24>", line 1, in <module>
        Table.to_sql(name = 'existingSQLTable', con = engine, if_exists = 'append', index = False, chunksize = 10000, dtype = dataTypes)
      File "C:\Apps\Anaconda3\lib\site-packages\pandas\core\generic.py", line 1165, in to_sql
        chunksize=chunksize, dtype=dtype)
      File "C:\Apps\Anaconda3\lib\site-packages\pandas\io\sql.py", line 571, in to_sql
        chunksize=chunksize, dtype=dtype)
      File "C:\Apps\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1250, in to_sql
        table.insert(chunksize)
      File "C:\Apps\Anaconda3\lib\site-packages\pandas\io\sql.py", line 770, in insert
        self._execute_insert(conn, keys, chunk_iter)
      File "C:\Apps\Anaconda3\lib\site-packages\pandas\io\sql.py", line 745, in _execute_insert
        conn.execute(self.insert_statement(), data)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 914, in execute
        return meth(self, multiparams, params)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\sql\elements.py", line 323, in _execute_on_connection
        return connection._execute_clauseelement(self, multiparams, params)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1010, in _execute_clauseelement
        compiled_sql, distilled_params
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1146, in _execute_context
        context)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1341, in _handle_dbapi_exception
        exc_info
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 202, in raise_from_cause
        reraise(type(exception), exception, tb=exc_tb, cause=cause)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 185, in reraise
        raise value.with_traceback(tb)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1116, in _execute_context
        context)
      File "C:\Apps\Anaconda3\lib\site-packages\sqlalchemy\engine\default.py", line 447, in do_executemany
        cursor.executemany(statement, parameters)

根据这些错误,对我来说,fast_executemany 标志似乎有问题,但我已经阅读了很多关于它的文档,并没有发现它有任何问题。

可能需要注意的事项:

  1. if_exists = 'replace' 不存在的表按预期工作
  2. if_exists = 'append' 不存在的表按预期工作
  3. if_exists = 'replace' 已经存在的表按预期工作
  4. 我的 DataFrame 大约有 300 万行和 25 列(主要是浮点数和一些短字符串)
  5. 我可以成功写入 900,000 行绝对最大值而不会导致 python 崩溃。
  6. 我正在使用 SQL Server、pandas 0.23.3、pyodbc 4.0.23(我也遇到与 4.0.22 相同的错误)、Jupyter Notebook(我也在 IDLE 中尝试过,结果相同)、Windows 10、 Python 3.5.1 和 Anaconda 3。

对我来说显而易见的解决方案是将 DataFrame 分成 900,000 行的块。当第一个块成功上传时,我什至不能在没有 python 崩溃的情况下附加一行。

此错误是否是旨在加快进程的代码的结果(它做得非常好)?我误解了 to_sql 函数吗?还是有其他事情发生?任何建议都会很棒!另外,如果有人有类似的问题,很高兴知道!

4

1 回答 1

1

正如@Jon Clements 解释的那样,问题在于有些行具有相同的主键(但这些行本身并不相同)。我使用了 pandas df.drop_duplicates 函数,将子集参数设置为主键列。这解决了违反PK错误。

于 2018-07-26T20:21:06.597 回答