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

时间:2019-02-20 20:14:44

标签: python pandas cx-oracle

情况:我正在将整个SQL表加载到程序中。为了方便起见,我使用熊猫来维护行数据。然后,我要创建一个要从SQL表中删除的行的数据框。不幸的是(而且我无法更改),该表除了内置的Oracle ROWID(不是真正的表列,而是伪列)之外没有任何主键,但是我可以如果需要的话,使ROWID成为数据框的一部分。

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

问题: 使用Cx_Oracle删除没有主键的多行/记录的最佳方法是什么?我不认为创建一个循环来提交数千个delete语句是非常有效或Python式的。尽管我担心要构建一个以ROWID为键的单一SQL删除语句,并且该语句包含一个包含数千个项目的子句:

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

此问题有效吗?有什么建议吗?

2 个答案:

答案 0 :(得分:1)

使用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

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

没有ROWID

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

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()的方式无疑更容易编写和执行,但出于速度考虑,单个大查询(以上两个查询中的任何一个)在执行数以千计的项目时的性能可能会优于执行。

答案 1 :(得分:0)

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

dataToDelete = [['eg1'], ['eg2'], ...., ['eg2345']]
cursor.executemany("delete from sometable where rowid = :1", dataToDelete)