mysql 如何在pyobdc/sqlalchemy中执行此Not In操作而不触发标记操作数溢出?

t3psigkw  于 2022-11-21  发布在  Mysql
关注(0)|答案(1)|浏览(118)

这是一个简化的案例:我有两个数据库,一个MySQL和一个MS_Access。我正在尝试从MsAccess中删除所有不在MySQL表中但仍在MSAccess中的元素。我正在使用sqlalchemy连接到这两个数据库。为了连接MSAccess(我知道,这个数据库不应该再使用了,这实际上是迁移过程的一部分),我正在使用sqlalchemy-access,它在内部与pyodbc一起工作。
执行此操作的代码为:

#every row in the mysql table contains a field that references its correspondent row in msaccess
mysql_ids = mysql_session.query(mysql_table.id_msaccess).all()
list_of_ids = [elem(0) for elem in mysql_ids]

delete_query = delete(access_table).where((access_table).id.not_in(list_of_ids))
results = access_session.execute(delete_query)

但是,我收到以下错误消息:
(pyodbc.ProgrammingError)('SQL包含-9972个参数标记,但提供了55564个参数)DELETE FROM [access_table] WHERE([access_table].[id] NOT IN(?,?,...〈此处有所有55564个参数标记〉)参数:(二四一、二四二、二四三......)
我在pyodbc的github页面上发现了这个问题:
Github Issue in Pyodbc
他们本质上是说在内部实现中有一个溢出的标记计数器。他们谈论的是SQL Server,但我猜这里也发生了同样的事情。
我可以在32768行的块中执行这个查询,或者检查mysql表中的每个元素,看看它是否在ms-access表中(我认为这会很慢),但是我想知道是否有更好的方法。关于如何处理这个问题,你有什么建议吗?
提前感谢您的任何建议

m2xkgtsf

m2xkgtsf1#

我可以在包含32768行的块中执行此查询
这对NOT IN查询不起作用。假设您有一个要保留的行列表:

[1, 2, 3, 4, 5, 6]

如果您尝试以3个为一批执行此操作,则第一个DELETE将是

DELETE FROM access_table WHERE id NOT IN (1, 2, 3)

这将删除ID值为4、5和6的行。然后,下一个DELETE将是

DELETE FROM access_table WHERE id NOT IN (4, 5, 6)

这将删除ID值为1、2和3的行。
但是,您可以构建要 * 删除 * 的行的列表,如下所示:

with mysql_engine.begin() as conn:
    mysql_existing = (
        conn.scalars(sa.select(mysql_table.c.id_msaccess)).all()
    )
    print(mysql_existing)  # [2, 3]

with access_engine.begin() as conn:
    access_existing = (
        conn.scalars(sa.select(access_table.c.id)).all()
    )
    print(access_existing)  # [1, 2, 3, 4, 5, 6]

access_to_delete = list(set(access_existing).difference(mysql_existing))
print(access_to_delete)  # [1, 4, 5, 6]

并且可以通过使用IN而不是NOTIN来批处理该列表。

相关问题