情况:我正在将整个SQL表加载到程序中。为了方便起见,我使用熊猫来维护行数据。然后,我要创建一个要从SQL表中删除的行的数据框。不幸的是(并且我无法更改)表除了内置的Oracle ROWID(不是真正的表列,而是伪列)之外没有任何主键,但是如果有的话,我可以使ROWID成为数据框的一部分我需要。
该表有成千上万的行,并且每次程序运行时我可能会删除几千条记录。
问题:使用Cx_Oracle删除没有主键的多行/记录的最佳方法是什么?我认为创建提交数千个delete语句的循环不是非常有效或pythonic。尽管我担心要构建一个以ROWID为键的单SQL删除语句,并且该语句包含一个包含数千个项目的子句:
Where ROWID IN ('eg1','eg2',........, 'eg2345')
这种担忧有效吗?有什么建议?
既然可以使用ROWID
,那将是理想的选择。并且,根据Oracle版本的不同,查询长度限制可能足够大,以至于IN
子句中具有这么多元素的查询。问题是该元素的个数在IN
表达式列表-仅限于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,则标识每一行的唯一方法是在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的情况下进行查询。
在这两种情况下,您可能都不需要使用参数化查询,因为IN
1中的列表或OR
2中的分组是可变的。(是的,您可以在构建具有数千个参数的整个扩展SQL之后,以参数化方式创建它。不确定此限制是什么。)这种executemany()
方式显然更容易编写和执行,但是为了提高速度,可以使用单个大型查询(上面的两个)可能会在成千上万个项目上胜过执行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句