5

我认为这几乎是不可能的或非常棘手的。我正在使用 CriteriaBuilder、JPA 2.0、Hibernate 和 MariaDB,并希望使用 CriteriaBuilder 构建以下查询:

SELECT COUNT(*) FROM
   (SELECT DISTINCT(SomeColumn) // I think this is not possible?
    FROM MyTable
    WHERE ... COMPLEX CLAUSE ...
    GROUP BY SomeColumn) MyTable

我的问题:可能吗?如果,如何?

感谢您解决这个问题!

标记

4

4 回答 4

5

此示例假定您正在使用元模型生成。

CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Subquery<SomeColumnType> subcq = cq.subquery(SomeColumnType.class);
Root<MyTable> from = subcq.from(MyTable.class);
subcq.select(from.get(MyTable_.someColumn));
subcq.where(** complex where statements **);
subcq.groupBy(from.get(MyTable_.someColumn));
cq.select(cb.count(subcq));
于 2012-06-25T07:00:54.617 回答
1

我有一个类似的问题,按元素计算不同的组,并偶然发现了这个线程,基于已经存在的答案我想出了以下

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
Root<Jpa1> countRoot = countQuery.from(Jpa1.class);

Subquery<Long> query = countQuery.subquery(Long.class);
Root<Jpa1> root = query.from(Jpa1.class);

applyFilter(query, root);
query.groupBy(root.get("groupBy_column1"), root.get("groupBy_column2"));
query.select(builder.min(root.get("id_column")));

countQuery.where(builder.in(countRoot.get("id_column")).value(query));
return countQuery.select(builder.count(countRoot.get("id_column")));
于 2021-07-14T08:22:40.810 回答
0

如果您有 Spring Boot 并且想要做同样的事情,那么有一个更好的解决方法,它只能通过使用本机SQL_CALC_FOUND_ROWSFOUND_ROWS(它不适用于 MySQL 8)适用于 MySql 5/Maria;

这种集成的主要思想是 Spring-Data 的灵活性和覆盖默认值的能力,JpaRepositoryFactoryBean如下所示

步骤 #1 - 创建自定义CustomJpaRepositoryFactoryBean

/**
* 
* @author ehakawati
*
* @param <R>
* @param <T>
* @param <I>
*/
public class CustomJpaRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
        extends JpaRepositoryFactoryBean<R, T, I> {

    public CustomJpaRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        RepositoryFactorySupport repositoryFactorySupport = super.createRepositoryFactory(entityManager);
        repositoryFactorySupport.setRepositoryBaseClass(CustomJpaRepository.class);
        return repositoryFactorySupport;
    }

}

步骤 #2 - 创建自定义CustomJpaRepository

 /**
 * 
 * @author ehakawati
 *
 * @param <T>
 * @param <ID>
 */
public class CustomJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
        implements Repository<T, ID> {

    private final EntityManager em;

    /**
     * 
     * @param entityInformation
     * @param entityManager
     */
    public CustomJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.em = entityManager;

    }

    /**
     * 
     * @param domainClass
     * @param entityManager
     */
    public CustomJpaRepository(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.em = entityManager;
    }

    /**
     * Reads the given {@link TypedQuery} into a {@link Page} applying the given
     * {@link Pageable} and {@link Specification}.
     *
     * @param query       must not be {@literal null}.
     * @param domainClass must not be {@literal null}.
     * @param spec        can be {@literal null}.
     * @param pageable    can be {@literal null}.
     * @return
     */
    protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
            @Nullable Specification<S> spec) {

        if (pageable.isUnpaged()) {
            return super.readPage(query, domainClass, pageable, spec);
        }

        query.setFirstResult((int) pageable.getOffset());
        query.setMaxResults(pageable.getPageSize());

        return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> getNativeCount());
    }

    /**
     * 
     */

    protected long getNativeCount() {

        final Query query = em.createNativeQuery("SELECT FOUND_ROWS() as `count`");

        return ((BigInteger) query.getSingleResult()).longValue();

    }

}

步骤#3 - PageableQueriesInterceptor

 /**
 * 
 * @author ehakawati
 *
 * @param <T>
 * @param <ID>
 */
public class PageableQueriesInterceptor extends EmptyInterceptor {

    private static final Pattern PATTERN = Pattern.compile(".*?limit \\?(, \\?)?$");
    private static final long serialVersionUID = 1L;

    @Override
    public String onPrepareStatement(String sql) {

        if (PATTERN.matcher(sql).find()) {
            sql = sql.replaceFirst("select", "select SQL_CALC_FOUND_ROWS ");
        }

        return sql;
    }
}

步骤 #4 - 启用PageableQueriesInterceptor

sprint.jpa.properties.hibernate.ejb.interceptor= com.****.****.******.betterpaging.PageableQueriesInterceptor

享受

于 2020-06-11T14:47:01.727 回答
0

CriteriaBuilder.countDistinct() 方法可以很好地计算 groupBy 结果。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);

Root<MyEntity> root = cq.from(MyEntity);
        
cq.select(cb.countDistinct(root("entityField")));
cq.where(** your criteria **);

var result = em.createQuery(cq).getSingleResult();
var m = Math.toIntExact(result);

这就像 SQL 查询

SELECT COUNT(DISTINCT myEntity.entityField) FROM myEntity WHERE **blah** ;

当然,countDistinct(如 COUNT(DISTINCT ...))可以根据需要列出多个列以用于分组目的。

于 2021-11-04T19:54:06.157 回答