如何在Java代码中解析ORA-01795

时间:2014-11-04 22:07:03

标签: java oracle

在IN子句中执行超过1000条记录时,我的Java代码出现ORA-01795错误。 我想在1000个条目的批处理中使用由OR子句分隔的多个IN子句来打破它,如下所示:

  select * from table_name
  where
  column_name in (V1,V2,V3,...V1000)
  or
  column_name in (V1001,V1002,V1003,...V2000)

我有一个字符串ID,如-18435,16690,1719,1082,1026,100759...,它会根据用户选择动态生成。如何在Java中编写1-1000条记录,1001条到2000条记录等条件的逻辑。谁能在这帮助我?

4 个答案:

答案 0 :(得分:3)

围绕此限制有三种可能的方式:

1)正如您已经提到过的那样:将批量声明分成1000份

2)使用值创建派生表,然后将它们连接起来:

with id_list (id) as (
  select 'V1' from dual union all
  select 'V2' from dual union all
  select 'V3' from dual
)
select *
from the_table
where column_name in (select id from id_list);

或者您也可以加入这些值 - 甚至可能更快:

with id_list (id) as (
  select 'V1' from dual union all
  select 'V2' from dual union all
  select 'V3' from dual
)
select t.*
from the_table t
  join id_list l on t.column_name = l.id;

这仍然会产生一个非常非常巨大的声明,但不会有1000个ids的限制。我不确定Oracle会解析这个问题的速度有多快。

3)将值插入(全局)临时表,然后使用IN子句(或JOIN)。这可能是最快的解决方案。

答案 1 :(得分:1)

我最近自己打了这堵墙:

Oracle在IN()

内的最大数量为1000个术语的架构限制

有两种解决方法:

  1. 将查询重构为联接
  2. 保持查询不变,但在循环中多次调用,每次调用少于1000个术语
  3. 选项1取决于具体情况。如果您的值列表来自查询,则可以重构为连接

    选项2也很简单,但性能较差:

    List<String> terms;
    for (int i = 0; i <= terms.size() / 1000; i++) {
        List<String> next1000 = terms.subList(i * 1000, Math.min((i + 1) * 1000, terms.size());
        // build and execute query using next1000 instead of terms
    }
    

答案 2 :(得分:1)

如果有这么多的值,我会避免inor以及嵌入值的硬解析惩罚,如果可能的话,在查询中。您可以传递一组SQL值集合,并使用table()集合表达式作为表格,您可以将真实表格加入。

这使用硬编码的整数数组作为示例,但您可以从用户输入填充该数组。我正在使用built-in collection type definitions,例如sys.odcinumberlist,我们使用varray数字并且限制为32k值,但如果您愿意或可能需要,您可以定义自己的表类型处理更多。

int[] ids = { -18435,16690,1719,1082,1026,100759 };
ArrayDescriptor aDesc = ArrayDescriptor.createDescriptor("SYS.ODCINUMBERLIST", conn );
oracle.sql.ARRAY ora_ids = new oracle.sql.ARRAY(aDesc, conn, ids);

sql = "select t.* "
    + "from table(?) a "
    + "left join table_name t "
    + "on t.column_name = a.column_value "
    + "order by id";
pStmt = (OraclePreparedStatement) conn.prepareStatement(sql);
pStmt.setArray(1, ora_ids);
rSet = (OracleResultSet) pStmt.executeQuery();
...

您的数组可以包含任意数量的值(嗯,与您使用的集合类型和JVM的内存可以处理的数量一样多)并且不受in列表的1000个成员限制的约束。< / p>

基本上table(?)最终看起来像一个包含所有值的表,这比使用所有值填充真实或临时表并加入其中更容易,更快。

当然,不要真正使用t.*,列出你需要的列;我假设您使用*来解释问题......

Here is a more complete example,但情节略有不同。)

答案 3 :(得分:0)

在这种情况下,当我在Java中使用List中的id时,我使用这样的实用程序类将列表拆分为分区并从这些分区生成语句:

public class ListUtils {
    public static <T> List<List<T>> partition(List<T> orig, int size) {
        if (orig == null) {
            throw new NullPointerException("The list to partition must not be null");
        }
        if (size < 1) {
            throw new IllegalArgumentException("The target partition size must be 1 or greater");
        }
        int origSize = orig.size();
        List<List<T>> result = new ArrayList<>(origSize / size + 1);
        for (int i = 0; i < origSize; i += size) {
            result.add(orig.subList(i, Math.min(i + size, origSize)));
        }
        return result;
    }
}

我们假设您的ID位于名为ids的列表中,您可以通过以下方式获取大小最多为1000的子列表:

ListUtils.partition(ids, 1000)

然后你可以迭代结果来构造最终的查询字符串。