删除匹配作为静态列表提供的多个值

时间:2014-07-28 09:52:08

标签: oracle

扩展这个问题 - Oracle Delete Rows Matching On Multiple Values,我需要使用两个列表中的DELETE ... WHERE ... IN ...,但我需要使用由外部语句提供的文本字符串,而不是{{1声明。

例如,我有这两个字符串:

  

'2810C000000635', '2810C000000636', '2810C000000637'

     

28006900,28006901,28006902

我希望将它们变成SQL。

SELECT

但是运行这个给了我: DELETE FROM os_abp_classification WHERE (class_key, uprn) IN ('2810C000000635','2810C000000636','2810C000000637'),(28006900,28006901,28006902)


这被问到Oracle multiple fields in Select IN Parameter - 但是给定的答案对我不起作用:

SQL Error: ORA-00920: invalid relational operator

DELETE FROM os_abp_classification where (class_key, uprn) IN ( SELECT '2810C000000635','2810C000000636','2810C000000637' from DUAL union SELECT 28006900,28006901,28006902 from DUAL )

此类查询的格式是什么?感谢

修改: 我正在尝试复制此功能,但使用“where ... in”格式,因为它更快(在Optimal way to DELETE specified rows from Oracle中发现):

ORA-00913: too many values

1 个答案:

答案 0 :(得分:2)

如果您要删除匹配对,则语法为:

DELETE FROM os_abp_classification
WHERE (class_key, uprn) IN (
  select '2810C000000635', 28006900 from dual
  union all select '2810C000000636', 28006901 from dual
  union all select '2810C000000637', 28006902 from dual
  union all ...
)

根据字符串的来源,您可以通过将它们分成单独的元素来使其更加通用

delete from os_abp_classification
where (class_key, uprn) in (
  with class_keys as (
    select level as rn,
      regexp_substr('2810C000000635,2810C000000636,2810C000000637',
        '[^,]+', 1, level) as class_key
    from dual
    connect by regexp_substr('2810C000000635,2810C000000636,2810C000000637',
      '[^,]+', 1, level) is not null
  ),
  uprns as (
    select level as rn,
      cast(regexp_substr('28006900,28006901,28006902',
        '[^,]+', 1, level) as number) as uprn
    from dual
    connect by regexp_substr('28006900,28006901,28006902',
      '[^,]+', 1, level) is not null
  )
  select ck.class_key, u.uprn
  from class_keys ck
  join uprns u on u.rn = ck.rn
);

样本数据的时间越长,但如果你有很多值对,它可能会缩短,你可能会根据你在哪里/如何运行它来绑定字符串值。

子查询使用CTE将每个原始值字符串转换为值列表 - 在第一个字符串中保留为字符串,在第二个字符串中转换为数字。它还为两个集合中的每个结果分配一个伪行号,对于匹配对,它们将是相同的,因此将CTE连接在一起可以为表格准备好in子句:

SQL Fiddle显示CTE联接的结果,基于此的删除以及之后剩余的行。


如果您已经有值列表,您也可以这样做:

delete from os_abp_classification
where (class_key, uprn) in (
  with class_keys as (
    select rownum as rn, column_value as class_key
    from table(sys.odcivarchar2list('2810C000000635','2810C000000636','2810C000000637'))
  ),
  uprns as (
    select rownum as rn, column_value as uprn
    from table(sys.odcinumberlist(28006900,28006901,28006902))
  )
  select ck.class_key, u.uprn
  from class_keys ck
  join uprns u on u.rn = ck.rn
);

...但在没有明确rownum的情况下依赖order by是有风险的;它looks OK here但可能无法保证可以正常工作,即使它现在可以正常工作,也可能在将来中断。 odcivarchar2list is definedvararry,这是一个有序集。我想Tom Kyte sort of implies it's OK too。但即便如此,我也要小心使用它。 (有足够的警告吗?)