是否有ORA-01795的解决方法:列表中的最大表达式数是1000错误?

val*_*t74 65 sql toad

是否有解决方法

'ORA-01795: maximum number of expressions in a list is 1000 error'

我有一个查询,它是根据一个字段的值选择字段.我使用的是in子句,有10000多个值

例:

select field1, field2, field3 
from table1 
where name in 
(
'value1',
'value2',
...
'value10000+'
);
Run Code Online (Sandbox Code Playgroud)

每次我执行查询时,我都会得到ORA-01795: maximum number of expressions in a list is 1000 error.我试图在TOAD中执行查询,没有区别,同样的错误.如何修改查询以使其工作?

提前致谢

Fab*_*ney 108

只需使用多个in-clauses来解决这个问题:

select field1, field2, field3 from table1 
where  name in ('value1', 'value2', ..., 'value999') 
    or name in ('value1000', ..., 'value1999') 
    or ...;
Run Code Online (Sandbox Code Playgroud)

  • 请记住,如果要使用NOT IN逻辑,则需要将这些语句一起与 (2认同)

小智 23

我最近遇到了这个问题并找到了一种厚颜无耻的方式,而没有将其他IN子句串联在一起

你可以使用元组

SELECT field1, field2, field3
FROM table1
WHERE (1, name) IN ((1, value1), (1, value2), (1, value3),.....(1, value5000));
Run Code Online (Sandbox Code Playgroud)

Oracle确实允许> 1000个元组,但不允许简单的值.更多相关信息,

https://community.oracle.com/message/3515498#3515498

https://community.oracle.com/thread/958612

当然,如果您没有在IN中使用子查询来从临时表中获取所需的值.


Ahm*_*OUR 18

一些解决方案解决方案是:

1-将IN子句拆分为多个IN子句,其中文字小于1000,并使用OR子句组合它们:

将原始"WHERE"子句从一个"IN"条件拆分为几个"IN"条件:

Select id from x where id in (1, 2, ..., 1000,…,1500);
Run Code Online (Sandbox Code Playgroud)

至:

Select id from x where id in (1, 2, ..., 999) OR id in (1000,...,1500);
Run Code Online (Sandbox Code Playgroud)

2-元组的使用:限制1000适用于单个项目集:(x)IN((1),(2),(3),...).如果集合包含两个或更多项目,则没有限制:(x,0)IN((1,0),(2,0),(3,0),...):

Select id from x where (x.id, 0) IN ((1, 0), (2, 0), (3, 0),.....(n, 0));
Run Code Online (Sandbox Code Playgroud)

3-临时表的使用:

Select id from x where id in (select id from <temporary-table>);
Run Code Online (Sandbox Code Playgroud)

  • 很好的总结.你知道各种选择之间是否存在性能差异? (2认同)

小智 7

请使用in-clause中的内部查询:

select col1, col2, col3... from table1
 where id in (select id from table2 where conditions...)
Run Code Online (Sandbox Code Playgroud)


sva*_*aor 7

还有一种方法:

CREATE OR REPLACE TYPE TYPE_TABLE_OF_VARCHAR2 AS TABLE OF VARCHAR(100);
-- ...
SELECT field1, field2, field3
  FROM table1
  WHERE name IN (
    SELECT * FROM table (SELECT CAST(? AS TYPE_TABLE_OF_VARCHAR2) FROM dual)
  );
Run Code Online (Sandbox Code Playgroud)

我不认为它是最佳的,但它的工作原理.提示/*+ CARDINALITY(...) */非常有用,因为Oracle不了解传递的数组的基数,也无法估计最佳执行计划.

作为另一种选择 - 批量插入临时表并使用子查询中的最后一个用于IN谓词.


Ada*_*dam 5

还有另一种选择:with语法。要使用 OP 示例,这将如下所示:

with data as (
  select 'value1' name from dual
  union all
  select 'value2' name from dual
  union all
...
  select 'value10000+' name from dual)
select field1, field2, field3 
from table1 t1
inner join data on t1.name = data.name;
Run Code Online (Sandbox Code Playgroud)

我遇到了这个问题。在我的例子中,我有一个 Java 数据列表,其中每个项目都有一个 item_id 和一个 customer_id。我在数据库中有两个表,分别订阅了各个客户的项目。我想获得所有订阅项目或该项目的客户的列表,以及项目 ID。

我尝试了三种变体:

  1. 从 Java 中进行多项选择(使用元组绕过限制)
  2. 带语法
  3. 临时表

选项 1:从 Java 中进行多项选择

基本上,我先

select item_id, token 
from item_subs 
where (item_id, 0) in ((:item_id_0, 0)...(:item_id_n, 0))
Run Code Online (Sandbox Code Playgroud)

然后

select cus_id, token 
from cus_subs 
where (cus_id, 0) in ((:cus_id_0, 0)...(:cus_id_n, 0))
Run Code Online (Sandbox Code Playgroud)

然后我用 cus_id 作为键和项目列表作为值在 Java 中构建一个 Map,并为每个找到的客户订阅添加(到从第一个选择返回的列表)所有具有该 item_id 的相关项目的条目。这是更混乱的代码

选项 2:with 语法

使用 SQL 一次性获取所有内容

with data as (
  select :item_id_0 item_id, :cus_id_0 cus_id
  union all
  ...
  select :item_id_n item_id, :cus_id_n cus_id )
select I.item_id item_id, I.token token
from item_subs I
inner join data D on I.item_id = D.item_id
union all
select D.item_id item_id, C.token token
from cus_subs C
inner join data D on C.cus_id = D.cus_id
Run Code Online (Sandbox Code Playgroud)

选项 3:临时表

创建一个包含三个字段的全局临时表:rownr(主键)、item_id 和 cus_id。在那里插入所有数据,然后运行与选项 2 非常相似的选择,但链接到临时表而不是with data

表现

不是一个完全科学的性能分析。

  • 我正在针对一个开发数据库运行,我的数据集中有 1000 多行我想要查找订阅。
  • 我只试过一个数据集。
  • 我和我的数据库服务器不在同一个物理位置。它不是那么远,但我确实注意到如果我从家里通过 VPN 尝试那么它会慢得多,即使它的距离相同(而且问题不是我的家庭互联网)。
  • 我正在测试完整调用,因此我的 API 调用另一个(也在开发中的同一实例中运行),它也连接到数据库以获取初始数据集。但这在所有三种情况下都是一样的。

天啊。

也就是说,临时表选项慢得多。因为在双所以慢。我的选项 1 为 14-15 秒,选项 2 为 15-16 秒,选项 3 为 30 秒。

我将在与数据库服务器相同的网络上再次尝试它们,并在有机会时检查是否会发生变化。