Java Oracle例外情况-“;列表中表达式的最大数量为1000“;

Java 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

我将字符串列表传递给我的查询(SQL查询已写入),以获取所需的数据。 但我有一个例外:

ora-01795列表中表达式的最大数量为1000


我检查了列表中是否有1000多个条目传递给查询in参数。

这是oracle对查询中列表传递次数的限制

  • 你得把你的问题切掉,否则
  • 改为在in子句中提供子查询/联接
  • 发件人:

    ORA-01795:列表中表达式的最大数量为1000个提示

    Burleson Consulting提供的Oracle错误提示(S.Karam)

    Oracle文档在ora-01795错误*:ora-01795最大值上记录了这一点 列表中的表达式数为1000原因:超过254列 或在列表中指定了表达式。措施:移除一些 列表中的表达式。在Oracle MOSC论坛中,Oracle用户 试图找到绕过错误代码ORA-01795的方法。伊斯 Oracle的Reem Munakash回答了这个问题:

    Oracle8中的限制是1000个表达式。有一个错误495555,存档 针对错误文本,给出错误的编号(254)。但是, 可能是进一步的限制,具体取决于您使用的工具。这个 sqlplus中有1000个表达式

    解决方法是使用子查询

    8.1.5中修复了有关错误消息的错误


    如果能够将查询中的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 + ") ";
        }
    }