Java Oracle例外情况-“;列表中表达式的最大数量为1000“;
我将字符串列表传递给我的查询(SQL查询已写入),以获取所需的数据。 但我有一个例外: ora-01795列表中表达式的最大数量为1000Java Oracle例外情况-“;列表中表达式的最大数量为1000“;,java,oracle,hibernate,ora-01795,Java,Oracle,Hibernate,Ora 01795,我将字符串列表传递给我的查询(SQL查询已写入),以获取所需的数据。 但我有一个例外: ora-01795列表中表达式的最大数量为1000 我检查了列表中是否有1000多个条目传递给查询in参数。这是oracle对查询中列表传递次数的限制 你得把你的问题切掉,否则 改为在in子句中提供子查询/联接 发件人: ORA-01795:列表中表达式的最大数量为1000个提示 Burleson Consulting提供的Oracle错误提示(S.Karam) Oracle文档在ora-01795错误*:o
我检查了列表中是否有1000多个条目传递给查询in参数。这是oracle对查询中列表传递次数的限制
如果能够将查询中的db端逻辑转换为存储过程,则可以向其传递更长的数组(集合) 你可以找到一个简单的例子如何做到这一点。指向文档的链接已过时,因此这里有一个指向9i文档的链接 还有SQL部分
create or replace type NUM_ARRAY as table of number;
create or replace
procedure give_me_an_array( p_array in num_array )
as
begin
for i in 1 .. p_array.count
loop
dbms_output.put_line( p_array(i) );
end loop;
end;
您可以创建一个临时表,并在
in
语句中插入要使用的值,然后将临时表与实际表连接起来 我解决了这个问题,将列表分成1000个大小的批次,并使用OR将其连接起来
e、 g。
ID的eid[]数组
如果我想执行这个查询
String sql = select * from employee where some conditions and empid in(eid)
我通过编写一小段代码重新编写了此查询:
String sql = select * from employee where some conditions and (
empid in(empid[0...999]) OR
empid in(empid[1000...1999]) OR
empid in(empid[2000...2999]) OR .... );
在使用hibernate时处理此错误,您必须通过将列表分成100个批次,然后加入各个结果来解决此问题(如上面的查询所示)
我不认为hibernate不处理这个问题是一个限制,因为这个问题可能不是另一个数据库(如MySQL或DB2)的问题。Hibernate是一个跨数据库的ORM框架。如果使用Oracle DB,在一个“where”条件下,列表中的元素不能超过1000个。因此,您可以在多个“where”条件中切掉您的“where”条件,并用“or”子句将它们连接起来 如果您使用的是hibernate标准,那么可以使用下面的Java方法来实现这一点。 只要在您使用过的地方替换代码即可
criteria.add(Restrictions.in(propertyName, mainList));
与
该方法是:
private void addCriteriaIn (String propertyName, List<?> list,Criteria criteria)
{
Disjunction or = Restrictions.disjunction();
if(list.size()>1000)
{
while(list.size()>1000)
{
List<?> subList = list.subList(0, 1000);
or.add(Restrictions.in(propertyName, subList));
list.subList(0, 1000).clear();
}
}
or.add(Restrictions.in(propertyName, list));
criteria.add(or);
}
private void addCriteriaIn(字符串属性名称、列表、条件)
{
析取或=限制。析取();
如果(list.size()>1000)
{
而(list.size()>1000)
{
列表子列表=列表。子列表(0,1000);
或.add(Restrictions.in(propertyName,subList));
子列表(0,1000).clear();
}
}
或.add(Restrictions.in(propertyName,list));
标准。添加(或);
}
使用Java Hibernate,为了解决这个问题,我决定更改Hibernate核心JAR。我创建了一个helper类,将一个表达式拆分为更多的联接,如:。。。t、 (:list_1)中的列或(:list_2)中的t.column.
,然后我将AbstractQueryImpl.expandParameterList方法从hibernate更改为在集合超过限制时调用我的方法我的hibernate核心版本是3.6.10.Final,但它运行良好,对于4.x版本,我进行了测试
我的代码将针对以下情况进行测试:
where t.id in (:idList)
where (t.id in (:idList))
where ((t.id) in (:idList))
where 1=1 and t.id in (:idList)
where 1=1 and (t.id in (:idList))
where 1=1 and(t.id) in (:idList)
where 1=1 and((t.id) in (:idList))
where 1=1 and(t.id in (:idList))
where t.id not in (:idList)
where (t.id not in (:idList))
where ((t.id) not in (:idList))
AbstractQueryImpl.expandParameterList:
private String expandParameterList(String query, String name, TypedValue typedList, Map namedParamsCopy) {
Collection vals = (Collection) typedList.getValue();
Type type = typedList.getType();
boolean isJpaPositionalParam = parameterMetadata.getNamedParameterDescriptor( name ).isJpaStyle();
String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
String placeholder =
new StringBuffer( paramPrefix.length() + name.length() )
.append( paramPrefix ).append( name )
.toString();
if ( query == null ) {
return query;
}
int loc = query.indexOf( placeholder );
if ( loc < 0 ) {
return query;
}
String beforePlaceholder = query.substring( 0, loc );
String afterPlaceholder = query.substring( loc + placeholder.length() );
// check if placeholder is already immediately enclosed in parentheses
// (ignoring whitespace)
boolean isEnclosedInParens =
StringHelper.getLastNonWhitespaceCharacter( beforePlaceholder ) == '(' &&
StringHelper.getFirstNonWhitespaceCharacter( afterPlaceholder ) == ')';
if ( vals.size() == 1 && isEnclosedInParens ) {
// short-circuit for performance when only 1 value and the
// placeholder is already enclosed in parentheses...
namedParamsCopy.put( name, new TypedValue( type, vals.iterator().next(), session.getEntityMode() ) );
return query;
}
// *** changes by Vasile Bors for HHH-1123 ***
// case vals.size() > 1000
if ((vals.size() >= InExpressionExpander.MAX_ALLOWED_PER_INEXPR) && isEnclosedInParens) {
InExpressionExpander inExpressionExpander = new InExpressionExpander(beforePlaceholder, afterPlaceholder);
if(inExpressionExpander.isValidInOrNotInExpression()){
List<String> list = new ArrayList<String>( vals.size() );
Iterator iter = vals.iterator();
int i = 0;
String alias;
while ( iter.hasNext() ) {
alias = ( isJpaPositionalParam ? 'x' + name : name ) + i++ + '_';
namedParamsCopy.put( alias, new TypedValue( type, iter.next(), session.getEntityMode() ) );
list.add(ParserHelper.HQL_VARIABLE_PREFIX + alias );
}
String expandedExpression = inExpressionExpander.expandExpression(list);
if(expandedExpression != null){
return expandedExpression;
}
}
}
// *** end changes by Vasile Bors for HHH-1123 ***
StringBuffer list = new StringBuffer(16);
Iterator iter = vals.iterator();
int i = 0;
while (iter.hasNext()) {
String alias = (isJpaPositionalParam ? 'x' + name : name) + i++ + '_';
namedParamsCopy.put(alias, new TypedValue(type, iter.next(), session.getEntityMode()));
list.append(ParserHelper.HQL_VARIABLE_PREFIX).append(alias);
if (iter.hasNext()) {
list.append(", ");
}
}
return StringHelper.replace(
beforePlaceholder,
afterPlaceholder,
placeholder.toString(),
list.toString(),
true,
true
);
}
private String expandParameterList(字符串查询、字符串名称、类型值类型列表、映射名称参数){
集合VAL=(集合)typedList.getValue();
Type Type=typedList.getType();
布尔isJpaPositionalParam=parameterMetadata.getNamedParameterDescriptor(名称).isJpaStyle();
字符串paramPrefix=isJpaPositionalParam?“:ParserHelper.HQL_变量_前缀;
字符串占位符=
新的StringBuffer(paramPrefix.length()+name.length())
.append(参数前缀).append(名称)
.toString();
if(查询==null){
返回查询;
}
int loc=query.indexOf(占位符);
如果(loc<0){
返回查询;
}
字符串beforep占位符=query.substring(0,loc);
字符串afterPlaceholder=query.substring(loc+placeholder.length());
//检查占位符是否已立即括在括号中
//(忽略空白)
布尔isEnclosedInParens=
StringHelper.getLastNonWhitespaceCharacter(占位符之前)=='('&&
StringHelper.getFirstNonWhitespaceCharacter(afterPlaceholder)==')';
如果(vals.size()==1&&IsEnclosedinParns){
//当只有1个值和
//占位符已包含在括号中。。。
namedParamScope.put(名称,新类型值(类型,vals.iterator().next(),session.getEntityMode());
返回查询;
}
//***Vasile Bors对HHH-1123的变更***
//机箱VAL.size()>1000
如果((vals.size()>=InExpressionExpander.MAX允许的值)&&isnClosedinparens){
InExpressionExpander InExpressionExpander=新的InExpressionExpander(前占位符、后占位符);
如果(inExpressionExpander.isValidInOrNotInExpression()){
列表=新的ArrayList(vals.size());
迭代器iter=vals.Iterator();
int i=0;
where t.id in (:idList)
where (t.id in (:idList))
where ((t.id) in (:idList))
where 1=1 and t.id in (:idList)
where 1=1 and (t.id in (:idList))
where 1=1 and(t.id) in (:idList)
where 1=1 and((t.id) in (:idList))
where 1=1 and(t.id in (:idList))
where t.id not in (:idList)
where (t.id not in (:idList))
where ((t.id) not in (:idList))
private String expandParameterList(String query, String name, TypedValue typedList, Map namedParamsCopy) {
Collection vals = (Collection) typedList.getValue();
Type type = typedList.getType();
boolean isJpaPositionalParam = parameterMetadata.getNamedParameterDescriptor( name ).isJpaStyle();
String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
String placeholder =
new StringBuffer( paramPrefix.length() + name.length() )
.append( paramPrefix ).append( name )
.toString();
if ( query == null ) {
return query;
}
int loc = query.indexOf( placeholder );
if ( loc < 0 ) {
return query;
}
String beforePlaceholder = query.substring( 0, loc );
String afterPlaceholder = query.substring( loc + placeholder.length() );
// check if placeholder is already immediately enclosed in parentheses
// (ignoring whitespace)
boolean isEnclosedInParens =
StringHelper.getLastNonWhitespaceCharacter( beforePlaceholder ) == '(' &&
StringHelper.getFirstNonWhitespaceCharacter( afterPlaceholder ) == ')';
if ( vals.size() == 1 && isEnclosedInParens ) {
// short-circuit for performance when only 1 value and the
// placeholder is already enclosed in parentheses...
namedParamsCopy.put( name, new TypedValue( type, vals.iterator().next(), session.getEntityMode() ) );
return query;
}
// *** changes by Vasile Bors for HHH-1123 ***
// case vals.size() > 1000
if ((vals.size() >= InExpressionExpander.MAX_ALLOWED_PER_INEXPR) && isEnclosedInParens) {
InExpressionExpander inExpressionExpander = new InExpressionExpander(beforePlaceholder, afterPlaceholder);
if(inExpressionExpander.isValidInOrNotInExpression()){
List<String> list = new ArrayList<String>( vals.size() );
Iterator iter = vals.iterator();
int i = 0;
String alias;
while ( iter.hasNext() ) {
alias = ( isJpaPositionalParam ? 'x' + name : name ) + i++ + '_';
namedParamsCopy.put( alias, new TypedValue( type, iter.next(), session.getEntityMode() ) );
list.add(ParserHelper.HQL_VARIABLE_PREFIX + alias );
}
String expandedExpression = inExpressionExpander.expandExpression(list);
if(expandedExpression != null){
return expandedExpression;
}
}
}
// *** end changes by Vasile Bors for HHH-1123 ***
StringBuffer list = new StringBuffer(16);
Iterator iter = vals.iterator();
int i = 0;
while (iter.hasNext()) {
String alias = (isJpaPositionalParam ? 'x' + name : name) + i++ + '_';
namedParamsCopy.put(alias, new TypedValue(type, iter.next(), session.getEntityMode()));
list.append(ParserHelper.HQL_VARIABLE_PREFIX).append(alias);
if (iter.hasNext()) {
list.append(", ");
}
}
return StringHelper.replace(
beforePlaceholder,
afterPlaceholder,
placeholder.toString(),
list.toString(),
true,
true
);
}
import org.hibernate.QueryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
/**
* Utility class for expand Hql and Sql IN expressions with a parameter with more than IN expression limit size (HHH-1123).
* <br/>
* It work for expression with formats:
* <pre>
*
* where t.id in (:idList)
* where (t.id in (:idList))
* where ((t.id) in (:idList))
* where 1=1 and t.id in (:idList)
* where 1=1 and (t.id in (:idList))
* where 1=1 and(t.id) in (:idList)
* where 1=1 and((t.id) in (:idList))
* where 1=1 and(t.id in (:idList))
*
* where t.id not in (:idList)
* where (t.id not in (:idList))
* where ((t.id) not in (:idList))
* </pre>
* <p/>
* Example:
* <pre>
* select t.id from tableOrEntity t where t.id IN (:idList)
* </pre
*
* @author Vasile Bors
* @since 13/12/2015.
*/
public class InExpressionExpander {
private static final Logger log = LoggerFactory.getLogger(InExpressionExpander.class);
public static final int MAX_ALLOWED_PER_INEXPR = 1000;
private static final int MAX_PARAMS_PER_INEXPR = 500;
private Stack<String> stackExpr = new Stack<String>();
private StringBuilder toWalkQuery;
private final String beforePlaceholder;
private final String afterPlaceholder;
private boolean wasChecked = false;
private boolean isEnclosedInParens = false;
private boolean isInExpr = false;
private boolean isNotInExpr = false;
public InExpressionExpander(String beforePlaceholder, String afterPlaceholder) {
this.toWalkQuery = new StringBuilder(beforePlaceholder);
this.beforePlaceholder = beforePlaceholder;
this.afterPlaceholder = afterPlaceholder;
}
public boolean isValidInOrNotInExpression() {
if (!wasChecked) {
String lastExpr = extractLastExpression();
if ("(".equals(lastExpr)) {
isEnclosedInParens = true;
lastExpr = extractLastExpression();
}
isInExpr = "in".equalsIgnoreCase(lastExpr);
}
wasChecked = true;
return isInExpr;
}
public String expandExpression(List paramList) {
if (isValidInOrNotInExpression()) {
final String lastExpr = extractLastExpression(false);
if ("not".equalsIgnoreCase(lastExpr)) {
isNotInExpr = true;
extractLastExpression(); //extract "not" and consume it
}
extractColumnForInExpression();
StringBuilder exprPrefixBuilder = new StringBuilder();
for (int i = stackExpr.size() - 1; i > -1; i--) {
exprPrefixBuilder.append(stackExpr.get(i)).append(' ');
}
if (!isEnclosedInParens) {
exprPrefixBuilder.append('(');
}
String expandedExpression = expandInExpression(exprPrefixBuilder, paramList);
String beforeExpression = getBeforeExpression();
String afterExpression = getAfterExpression();
String expandedQuery = new StringBuilder(beforeExpression).append(expandedExpression)
.append(afterExpression)
.toString();
if (log.isDebugEnabled()) {
log.debug(
"Query was changed to prevent exception for maximum number of expression in a list. Expanded IN expression query:\n {}",
expandedExpression);
log.debug("Expanded query:\n {}", expandedQuery);
}
return expandedQuery;
}
log.error("Illegal call of InExpressionExpander.expandExpression() without IN expression.");
return null;
}
private String expandInExpression(StringBuilder exprPrefixBuilder, List values) {
String joinExpr = isNotInExpr ? ") and " : ") or ";
StringBuilder expr = new StringBuilder(16);
Iterator iter = values.iterator();
int i = 0;
boolean firstExpr = true;
while (iter.hasNext()) {
if (firstExpr || i % MAX_PARAMS_PER_INEXPR == 0) {
//close previous expression and start new expression
if (!firstExpr) {
expr.append(joinExpr);
} else {
firstExpr = false;
}
expr.append(exprPrefixBuilder);
} else {
expr.append(", ");
}
expr.append(iter.next());
i++;
}
expr.append(')');// close for last in expression
return expr.toString();
}
/**
* Method extract last expression parsed by space from toWalkQuery and remove it from toWalkQuery;<br/>
* If expression has brackets it will return al content between brackets and it will add additional space to adjust splitting by space.
*
* @return last expression from toWalkQuery
*/
private String extractLastExpression() {
return extractLastExpression(true);
}
/**
* Method extract last expression parsed by space from toWalkQuery, remove it from toWalkQuery if is consume = true;<br/>
* If expression has brackets it will return al content between brackets and it will add additional space to adjust splitting by space.
*
* @param consum if true the method will extract and remove last expression from toWalkQuery
* @return last expression from toWalkQuery
*/
private String extractLastExpression(final boolean consum) {
int lastIndex = this.toWalkQuery.length() - 1;
String lastExpr;
int exprSeparatorIndex = this.toWalkQuery.lastIndexOf(" ");
if (lastIndex == exprSeparatorIndex) { //remove last space from the end
this.toWalkQuery.delete(exprSeparatorIndex, this.toWalkQuery.length());
return extractLastExpression(consum);
} else {
lastExpr = this.toWalkQuery.substring(exprSeparatorIndex + 1, this.toWalkQuery.length());
if (lastExpr.length() > 1) {
if (lastExpr.endsWith(")")) {
//if parens are closed at the end we need to find where it is open
int opensParens = 0;
int closedParens = 0;
int startExprIndex = -1;
char c;
for (int i = lastExpr.length() - 1; i > -1; i--) {
c = lastExpr.charAt(i);
if (c == ')') {
closedParens++;
} else if (c == '(') {
opensParens++;
}
if (closedParens == opensParens) {
startExprIndex = i;
break;
}
}
if (startExprIndex > -1) {
lastExpr = lastExpr.substring(startExprIndex, lastExpr.length());
exprSeparatorIndex = exprSeparatorIndex + startExprIndex
+ 1; // +1 because separator is not space and don't must be deleted
}
} else if (lastExpr.contains("(")) {
int parentsIndex = exprSeparatorIndex + lastExpr.indexOf('(') + 1;
this.toWalkQuery.replace(parentsIndex, parentsIndex + 1, " ( ");
return extractLastExpression(consum);
}
}
if (consum) {
this.toWalkQuery.delete(exprSeparatorIndex, this.toWalkQuery.length());
}
}
if (consum) {
stackExpr.push(lastExpr);
}
return lastExpr;
}
private String extractColumnForInExpression() {
String column = extractLastExpression();
String beforeColumn = extractLastExpression(false);
long pointIndx = beforeColumn.lastIndexOf('.');
if (pointIndx > -1) {
if (pointIndx == (beforeColumn.length() - 1)) {
throw new QueryException(
"Invalid column format: " + beforeColumn + ' ' + column
+ " . Remove space from column!");
}
}
return column;
}
private String getBeforeExpression() {
return this.toWalkQuery + " (";
}
private String getAfterExpression() {
if (StringHelper.getFirstNonWhitespaceCharacter(afterPlaceholder) == ')') {
return afterPlaceholder;
}
return afterPlaceholder + ") ";
}
}