如何从没有主键的Oracle表中删除大量记录

问题描述 投票:1回答:2

情况:我正在将整个SQL表加载到我的程序中。为方便起见,我使用pandas来维护行数据。然后我创建了一个我希望从SQL表中删除的行的数据帧。不幸的是(我无法改变这一点)除了内置的Oracle ROWID(它不是真正的表列,它是一个伪列)之外,该表没有任何主键,但我可以将ROWID作为我的数据帧的一部分我需要。

该表有数十万行,我可能会在每次运行程序时删除几千条记录。

问题:使用Cx_Oracle删除没有主键的多行/记录的最佳方法是什么?我不认为创建一个提交数千个删除语句的循环非常有效或pythonic。虽然我担心构建一个单独的SQL删除语句键入ROWID并包含一个包含数千项的子句:

Where ROWID IN ('eg1','eg2',........, 'eg2345')

这个问题是否有效?有什么建议?

python pandas cx-oracle
2个回答
1
投票

Using ROWID

既然你可以使用ROWID,那将是理想的做法。并且根据Oracle版本,查询长度限制可能足够大,以便在IN子句中使用那么多元素进行查询。问题是IN表达式列表中的元素数量 - limited to 1000

因此,您要么必须一次将RowID列表分成1000个集合,要么一次只删除一行;有或没有executemany()

>>> len(delrows)  # rowids to delete
5000
>>> q = 'DELETE FROM sometable WHERE ROWID IN (' + ', '.join(f"'{row}'" for row in delrows) + ')'
>>> len(q)  # length of the query
55037
>>> # let's try with just the first 1000 id's and no extra spaces
... q = 'DELETE FROM sometable WHERE ROWID IN (' + ','.join(f"'{row}'" for row in delrows[:1000]) + ')'
>>> len(q)
10038

您可能在查询长度限制内,甚至可以使用最小的','项目分隔符保存一些字符。

Without ROWID

如果没有主键或ROWID,标识每一行的唯一方法是指定WHERE子句中的所有列并一次执行多行,它们需要一起进行OR运算:

DELETE FROM sometable
WHERE  ( col1 = 'val1'
         AND col2 = 'val2'
         AND col3 = 'val3' )  -- row 1
    OR ( col1 = 'other2'
         AND col2 = 'value2'
         AND col3 = 'val3' )  -- row 2
    OR ( ... )                -- etc

正如您所看到的,它不是最好的构造查询,但允许您在没有ROWID的情况下执行此操作。


在这两种情况下,您可能不需要使用参数化查询,因为1中的IN列表或2中的OR分组是可变的。 (是的,您可以在构建具有数千个参数的整个扩展SQL之后创建参数化。不确定该限制是什么。)executemany()方式肯定更容易编写和执行但速度快,单个大型查询(以上两个)可能会超过executemany成千上万的项目。


0
投票

您可以使用cursor.executemany()一次删除多行。像下面这样的东西应该工作:

dataToDelete = [['eg1'], ['eg2'], ...., ['eg2345']]
cursor.executemany("delete from sometable where rowid = :1", dataToDelete)
© www.soinside.com 2019 - 2024. All rights reserved.