ORA-01795异常(where in超过1000)的解决

6 篇文章 1 订阅

本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!
摘要:本文简述了Oracle数据库报ORA-01795异常的解决方案,并提供了可以直接使用的源代码供读者参考。

1 问题描述

在许多基于关系数据库开发的管理系统中会用到动态sql。即在java代码中根据业务语义动态拼接sql语句,执行后得到对应结果集或实现对表的操作。
对于使用Oracle数据库的系统,如果我们在拼接where in时,其item的个数超过1000,在sql执行时会抛出ORA-01795异常。该异常的描述如下:
ORA-01795
如果业务系统开放了用户建模、业务配置等功能,在进行了某些“不可思议”的配置后该现象是很可能出现的。当然,对于批量操作和检查则更容易出现这个问题。

2 解决问题的基础方式

解决该问题的基础方式是将原sql语句转换为等价的对Oracle合法的sql语句。对于where column in (A,B,C,D……) 这样的语句,where column in (A,B……) or column in(C,D……)是完全等价的。我们需要做的只是将item按照每1000个一组进行分组。
下面给出实现代码。

/**
     * 获取where in语句
     *
     * @param column      字段名
     * @param values      值集合
     * @return where in语句
     */
    private String GetWhereInValuesSql(String column, List<String> values) {
        // sql语句
        String sql = "(";
        // 值的个数
        int valueSize = values.size();
        // 批次数
        int batchSize = valueSize / 1000 + (valueSize % 1000 == 0 ? 0 : 1);
        for (int i = 0; i < batchSize; i++) {
            if (i > 0) {
                sql += ") or ";
            }
            sql += column+" in (";
            for (int j = i * 1000; ( j < (i + 1) * 1000) && j < valueSize; j++) {
                if (j > i * 1000) {
                    sql += ",";
                }
                sql += "'" + values.get(j) + "'";
            }
        }
        sql += "))";
        return sql;
    }

3 解决问题的进阶方式

如果where in语句中的item数量巨大,则应该进一步使用批量提交。比如在TiEAF中,我们为在JDBC基础上封装的数据库访问类添加了处理where in的批量获取和批量更新方法。其原理是:

  1. 根据每批查找量生成sql,数据部分使用占位符;
  2. 使用二维数组对要查找的item整组的数据(可整除部分)进行分组,作为绑定参数;
  3. 执行批量查询;
  4. 对求模运算的余数部分编写单独的sql语句,数据部分使用占位符;
  5. 将剩余item数据组织成参数数组;
  6. 执行单查询;
  7. 合并、返回结果;

鉴于保密问题,该部分无法提供源码,请读者见谅。

4 扩展

4.1 where not in
对于where column ont in (A,B,C,D……) 这样的语句,与其等价的是where column not in (A,B……) and column not in(C,D……)。
4.2 封装形式
在实际代码中,每批的item数、“where in或where not in”均应作为方法参数以最大化重用代码。在实际的代码中,我们也是这样封装的。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值