ORA-01795: maximum number of expressions in a list is 1000怎么处理,之前也陆陆续续查过一些方法,汇总整理一把。当然,其中的一些方法只是保证它不报错,性能可能堪忧,尽量少用。

select * from table1 where ID in (1,2,3,4,...,1001,1002,...);

一、 拆分/拼接SQL

1. 拆分循环执行

       例如有10000个值要in,就拆成10个20个语句循环执行,然后再处理结果。如果能拆得比较小,SQL能走上索引,其实还可以;如果拆出来都是大表走全表扫描,那就窒息了。

       还遇到过有种极致的拆法:拆成一条条ID=xxx去执行,如果数据量大,通常性能不如小批量的in,还是需要测试出一个合适的值。

2. or拼接SQL

select * from table1 where ID in (1,2,3,4,...,1000) or ID in (1001,1002,...,2000)

思路简单,但要对代码做一定改造,另外如果拼得太长,解析耗时和内存占用也够呛。

3. union all

select * from table1 where ID in (1,2,3,4,...,1000)
union all
select * from table1 where ID in (1001,1002,...)

优缺点跟上面类似

二、 使用临时表关联

1. 可以直接改为关联

       有些神奇的程序从某个/些表里查出来一堆结果,存到列表里,再放到另一个表的in中。相对来说这是最好改的,通常直接改为表关联,或者将结果插入临时表后进行关联即可。

select where id in (select id from temptable);

2. 构造临时表

       还遇到过in中的数据是从缓存中取出、或者程序构造的,并不在DB的表里,就需要先构造。可以是直接insert,也可以利用变量+CTE,例如:

var b1 varchar2(2000);
exec :b1:='1,2,3,…,1002';

with str_list as
(select cast(REGEXP_SUBSTR( :b1,'[^,]+', 1, level) as number) as value
from dual
connect by level <= regexp_count(:b1, '[^,]+')
)
SELECT object_name FROM t1
where t1.object_id in (select value from str_list);

当然,如果in中的字符很长,很可能变量长度hold不住。

三、 多行多列子查询

       名字叫Multiple Row and Column Subqueries,使用这种语法,in中值的上限可以到10万而不是1000,足够满足绝大多数业务场景。当然,如果真的in 10万个值,性能绝对够呛,慎用…

select column_X, ... from my_table
where ('magic', column_X ) in (
        ('magic', 1),
        ('magic', 2),
        ('magic', 3),
        ('magic', 4),
             ...
        ('magic', 99999)
    )

简单例子

with grades as (
  select 'Jim' usr, 'B' grade from dual
  union all
  select 'Bill', 'C' from dual
  union all
  select 'Tim', 'A' from dual
  union all
  select 'Jim', 'B+' from dual
)
select *
  from grades
 where (usr,grade) in (('Jim','B'),
                       ('Tim','C'),
                       ('Tim','A'));

后面如果学到新方法,再继续补充了~

参考

How to put more than 1000 values into an Oracle IN clause - Stack Overflow

Is it possible to compare tuples in oracle-compatible sql? - Stack Overflow

《专题培训-SQL写法与改写》