93

是否有解决方法

'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+'
);

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

提前致谢

4

14 回答 14

137

只需使用多个子句来解决这个问题:

select field1, field2, field3 from table1 
where  name in ('value1', 'value2', ..., 'value999') 
    or name in ('value1000', ..., 'value1999') 
    or ...;
于 2013-07-24T20:39:42.633 回答
38

一些解决方法是:

1.拆分IN子句

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

将原始“WHERE”子句从一个“IN”条件拆分为多个“IN”条件:

Select id from x where id in (1, 2, ..., 1000,…,1500);

至:

Select id from x where id in (1, 2, ..., 999) OR id in (1000,...,1500);

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));

3.使用临时表

Select id from x where id in (select id from <temporary-table>);
于 2015-09-07T13:46:13.880 回答
26

我最近遇到了这个问题,并想出了一种厚颜无耻的方法,而无需将额外的 IN 子句串在一起

你可以使用元组

SELECT field1, field2, field3
FROM table1
WHERE (1, name) IN ((1, value1), (1, value2), (1, value3),.....(1, value5000));

Oracle 确实允许 >1000 个元组,但不允许简单值。更多关于这里,

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

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

这当然是如果您无法选择在 IN 中使用子查询从临时表中获取所需的值。

于 2014-10-06T19:52:42.507 回答
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)
  );

我不认为它是最佳的,但它有效。该提示/*+ CARDINALITY(...) */将非常有用,因为 Oracle 不了解传递的数组的基数并且无法估计最佳执行计划。

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

于 2014-09-19T16:50:23.883 回答
7

请在 - 子句中使用内部查询in

select col1, col2, col3... from table1
 where id in (select id from table2 where conditions...)
于 2014-07-11T05:49:56.483 回答
5

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

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;

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

我尝试了三种变体:

  1. Java 中的多项选择(使用元组绕过限制)
  2. With-语法
  3. 临时表

选项 1:Java 中的多项选择

基本上,我首先

select item_id, token 
from item_subs 
where (item_id, 0) in ((:item_id_0, 0)...(:item_id_n, 0))

然后

select cus_id, token 
from cus_subs 
where (cus_id, 0) in ((:cus_id_0, 0)...(:cus_id_n, 0))

然后,我用 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

选项 3:临时表

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

表现

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

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

YMMV。

也就是说,临时表选项慢得多。像双那么慢。选项 1 得到 14-15 秒,选项 2 得到 15-16 秒,选项 3 得到 30 秒。

我会从与数据库服务器相同的网络再次尝试它们,并在有机会时检查是否会改变事情。

于 2018-01-15T13:52:27.503 回答
4

我意识到这是一个老问题,并且指的是 TOAD,但是如果您需要使用 c# 围绕这个进行编码,您可以通过 for 循环拆分列表。您基本上可以使用 subList(); 对 Java 做同样的事情;

    List<Address> allAddresses = GetAllAddresses();
    List<Employee> employees = GetAllEmployees(); // count > 1000

    List<Address> addresses = new List<Address>();

    for (int i = 0; i < employees.Count; i += 1000)
    {
        int count = ((employees.Count - i) < 1000) ? (employees.Count - i) - 1 : 1000;
        var query = (from address in allAddresses
                     where employees.GetRange(i, count).Contains(address.EmployeeId)
                     && address.State == "UT"
                     select address).ToList();

        addresses.AddRange(query);
    }

希望这可以帮助某人。

于 2015-08-18T20:31:47.437 回答
3

还有另一种方法可以解决这个问题。假设您有两个表 Table1 和 Table2。并且需要使用 Criteria 查询来获取 Table1 中未引用/存在于 Table2 中的所有条目。所以就这样继续吧……

List list=new ArrayList(); 
Criteria cr=session.createCriteria(Table1.class);
cr.add(Restrictions.sqlRestriction("this_.id not in (select t2.t1_id from Table2 t2 )"));
.
.

. . . 它将直接在 SQL 中执行所有子查询功能,而无需在由 Hibernate 框架转换的 SQL 中包含 1000 个或更多参数。它对我有用。注意:您可能需要根据您的要求更改 SQL 部分。

于 2013-07-25T07:29:06.103 回答
3

运营联盟

select * from tableA where tableA.Field1 in (1,2,...999)
union
select * from tableA where tableA.Field1 in (1000,1001,...1999)
union
select * from tableA where tableA.Field1 in (2000,2001,...2999)
于 2016-09-27T07:30:16.730 回答
2
    **Divide a list to lists of n size**

    import java.util.AbstractList;
    import java.util.ArrayList;
    import java.util.List;

    public final class PartitionUtil<T> extends AbstractList<List<T>> {

        private final List<T> list;
        private final int chunkSize;

        private PartitionUtil(List<T> list, int chunkSize) {
            this.list = new ArrayList<>(list);
            this.chunkSize = chunkSize;
        }

        public static <T> PartitionUtil<T> ofSize(List<T> list, int chunkSize) {
            return new PartitionUtil<>(list, chunkSize);
        }

        @Override
        public List<T> get(int index) {
            int start = index * chunkSize;
            int end = Math.min(start + chunkSize, list.size());

            if (start > end) {
                throw new IndexOutOfBoundsException("Index " + index + " is out of the list range <0," + (size() - 1) + ">");
            }

            return new ArrayList<>(list.subList(start, end));
        }

        @Override
        public int size() {
            return (int) Math.ceil((double) list.size() / (double) chunkSize);
        }
    }





Function call : 
              List<List<String>> containerNumChunks = PartitionUtil.ofSize(list, 999)

更多细节:https ://e.printstacktrace.blog/divide-a-list-to-lists-of-n-size-in-Java-8/

于 2020-04-28T10:30:33.813 回答
0

还有一种解决方法可以分离您的数组,对我有用,因为使用某些旧框架很难实现其他解决方案。

select * from tableA where id = 1 or id = 2 or id = 3 ...

但为了获得更好的性能,如果可能的话,我会使用 Nikolai Nechai 的工会解决方案。

于 2019-06-01T22:02:15.530 回答
0

通过列表和循环中需要返回的记录数大多数情况= 999。

List<List<Long>> getSubLists = batchList(inputList, 999);
List<Long> newList = new ArrayList<>();
for (List<Long> subSet : getSubLists) { newList.addALL(daoCall) // add in the required list in loop }

 public static <T> List<List<T>> batchList(List<T> inputList, final int maxSize) {
    List<List<T>> sublists = new ArrayList<>();
    final int size = inputList.size();
    for (int i = 0; i < size; i += maxSize) {
        sublists.add(new ArrayList<>(inputList.subList(i, Math.min(size, i + maxSize))));
    }
    return sublists;
}








  
于 2021-06-18T19:41:14.237 回答
0

使用元组:

假设输入是:

List<Long> userIdList = Arrays.asList(100L,200L,300L);

StringBuilder tuple = new StringBuilder();
for(Long userId : userIdList) {
   tuple.append("(1,").append(userId).append("),");
}
tuple.deleteCharAt(tuple.length()-1);

输出将是:(1,100),(1,200),(1,300)

我们可以像这样将它传递给下面的查询(是的,我们可以传递超过 1000 个元素):

SELECT * FROM MyTable WHERE (1, USR_ID) IN ((1,100),(1,200),(1,300));
于 2021-08-26T18:53:00.860 回答
0

ORA-01795: 列表中的最大表达式数为 1000。

问题: 当用户为 where 子句的 IN/OR 列表选择长值列表(大于或等于 1000 个值/表达式)时,系统抛出错误:“ORA-01795:列表中的最大表达式数为 1000”</p >

根本原因: Oracle IN / OR 列表的表达式/值列表的数量限制为 1000(实际上是 999)。

建议的解决方案: 您需要将表达式列表拆分为多个集合(使用 OR),并且每个集合应少于 1000 个列表/表达式组合,使用 IN / Or 列表。

示例: 假设您有一个表 ABC,其列 ZIP 为 CLOB 类型,并且表包含超过 1000 行。

您需要将它们分成多个列表,如下所示:

(邮编 (1,2,3,.......N999) 或邮编 (1000,1001,....N999) .....)

于 2022-02-19T21:31:23.267 回答