最近在修改产品bug时碰到了Oracle in列表过长问题。Google了一下原来是Oracle Sql语句中in列表不能超过1000项。网上的解决办法有很多,比较好的就是将in列表用or分开。我也采用这种方法,只不过我面对的只是in列表中的String,生成的String由外部程序加入in列表中。因此采用了特殊的处理方法。
主程序中加入以下分支
if
(iLen
>=
1000
)
... {
sql = getSql4LongCorps(corps);
}
else
... {
//正常处理
}
... {
sql = getSql4LongCorps(corps);
}
else
... {
//正常处理
}
其中新增了两个方法:
/** */
/**
* 对超长的下级公司数组特殊处理,并返回拼接后的in部分
* @author: yza
* @param:下级公司数组
* @return:用or拼接的in语句
*/
private String getSql4LongCorps(CorpVO[] corps)
... {
try
...{
StringBuilder strAll = new StringBuilder("select pk_corp from bd_corp where pk_corp ");
String sqlPart = "";
//in特殊处理
List<List<CorpVO>> corpList = splitArray(corps,500);
for(int k = 0;k<corpList.size();k++)
...{
List<CorpVO> arr = corpList.get(k);
for (int i = 0; i < arr.size(); i++)
...{
sqlPart += "'" + arr.get(i).getPrimaryKey() + "'";
if (i < arr.size() - 1)
sqlPart += ",";
}
strAll.append( " in (" + sqlPart + ")");
sqlPart = "";
if(k<corpList.size()-1)
...{
strAll.append(" or pk_corp ");
}
}
return strAll.toString();
}
catch(Exception e)
...{
e.printStackTrace();
return "";
}
}
/** */ /**
* 将大数组拆成小数组并返回存放数组的列表
* @author:yza
* @param:下级公司数组
* @param:分割后数组大小
* @return:包含分割后数组的List<T>
*/
private List < List < CorpVO >> splitArray(CorpVO[] corps, int perLength)
... {
int arrayNum = (corps.length/perLength) + 1;
List<List<CorpVO>> corpArrays = new ArrayList<List<CorpVO>>();
List<CorpVO> corpList = Arrays.asList(corps);
int start = 0;
int end = perLength;
for(int i = 0; i<arrayNum;i++)
...{
if(i == arrayNum -1)
...{
perLength = corps.length % perLength;
}
end = start + perLength;
List<CorpVO> part = corpList.subList(start, end);
//CorpVO[] a = part.toArray(new CorpVO[part.size()]);
corpArrays.add(part);
start = end;
}
return corpArrays;
}
* 对超长的下级公司数组特殊处理,并返回拼接后的in部分
* @author: yza
* @param:下级公司数组
* @return:用or拼接的in语句
*/
private String getSql4LongCorps(CorpVO[] corps)
... {
try
...{
StringBuilder strAll = new StringBuilder("select pk_corp from bd_corp where pk_corp ");
String sqlPart = "";
//in特殊处理
List<List<CorpVO>> corpList = splitArray(corps,500);
for(int k = 0;k<corpList.size();k++)
...{
List<CorpVO> arr = corpList.get(k);
for (int i = 0; i < arr.size(); i++)
...{
sqlPart += "'" + arr.get(i).getPrimaryKey() + "'";
if (i < arr.size() - 1)
sqlPart += ",";
}
strAll.append( " in (" + sqlPart + ")");
sqlPart = "";
if(k<corpList.size()-1)
...{
strAll.append(" or pk_corp ");
}
}
return strAll.toString();
}
catch(Exception e)
...{
e.printStackTrace();
return "";
}
}
/** */ /**
* 将大数组拆成小数组并返回存放数组的列表
* @author:yza
* @param:下级公司数组
* @param:分割后数组大小
* @return:包含分割后数组的List<T>
*/
private List < List < CorpVO >> splitArray(CorpVO[] corps, int perLength)
... {
int arrayNum = (corps.length/perLength) + 1;
List<List<CorpVO>> corpArrays = new ArrayList<List<CorpVO>>();
List<CorpVO> corpList = Arrays.asList(corps);
int start = 0;
int end = perLength;
for(int i = 0; i<arrayNum;i++)
...{
if(i == arrayNum -1)
...{
perLength = corps.length % perLength;
}
end = start + perLength;
List<CorpVO> part = corpList.subList(start, end);
//CorpVO[] a = part.toArray(new CorpVO[part.size()]);
corpArrays.add(part);
start = end;
}
return corpArrays;
}
其中getSql4LongCorps方法是主体,作用就是拼in中的超长Sql。参数 corps是集团下级分公司数组,就是这个数组长度超过了1000项,所以主程序中的else按常规拼出来的Sql才会报错。
splitArray函数是个通用方法。作用是将指定的数组拆成几个小数组,并允许调用者指定小数组的长度。搜遍整个Java类库也没有找到直接可用的方法(好像C#里也没有相关的方法)。以后会将它写成扩展方法放到框架中。(这里指.Net领域)。