gpt4 book ai didi

java - EclipseLink JPQL : Generic COUNT statement for any statement

转载 作者:行者123 更新时间:2023-12-02 12:07:20 29 4
gpt4 key购买 nike

我有一个用 JPQL 编写的应用程序,它可以命中非常不同的查询(在不同的资源上)。

对于很多此类查询,我需要知道结果总数(计数),因为我没有应用任何 LIMIT/OFFSET

由于此查询的性质非常不同,我无法构建一个解析器来提取 FROM 子句并将其应用于 SELECT COUNT 查询。

让我们看一个例子:

  • 查询 1:SELECT a FROM People a WHERE name = 'John'

  • 查询 2:SELECT DISTINCT(o.category.id) FROM Company o

尝试使用标准模式,计数查询将是SELECT (COUNT) z FROM (...) z 并在缺少的部分内我会将完整查询作为前面的 2

查询 1:SELECT COUNT(z) FROM (SELECT a FROM People a WHERE name = 'John') z查询 2:SELECT COUNT(z) FROM (SELECT DISTINCT(o.category.id) FROM Company o) z

从文档中我可以看到支持 FROM 子句中的子选择:https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause

这是我制作的示例代码

try {
String subSelect = "SELECT a FROM People a WHERE name = 'John'";
String statement = "SELECT COUNT(z) FROM (" + subSelect + ") z";
TypedQuery<Long> createQuery = em.createQuery(statement, Long.class);
System.out.println(createQuery.getSingleResult().longValue());
} finally {
em.close();
}

但是如果我尝试执行查询(我使用的是 EclipseLink 2.7.0),我会收到此错误:

java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: 
Exception Description: Problem compiling [SELECT COUNT(z) FROM (SELECT a FROM People a WHERE name = 'John') z].
[21, 67] '(SELECT a FROM People a WHERE name = 'John') z' cannot be the first declaration of the FROM clause.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1743)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1764)

即使似乎支持子选择,也不能是 FROM 子句的第一个声明。错误很明显。

我做错了什么吗?

我的最终目标是尝试拥有一个标准的 COUNT 查询,我可以将其用于任何类型的语句,只需使用 COUNT(*) FROM (..statement..) ,这样实现就非常通用了。

或者,如果有可以实现相同目标的方法,也可能很有用。

<小时/>

编辑

还按照建议尝试使用COUNT(0)',如下所示:SELECT COUNT(0) FROM (SELECT DISTINCT(o.category.id) FROM Company o)`

Exception Description: Syntax error parsing [SELECT COUNT(0) FROM (SELECT DISTINCT(o.category.id) FROM Company o)]. 
[68, 68] An identification variable must be provided for a range variable declaration.

最佳答案

根据@chris的建议,我想出了以下解决方案

    /**
* https://stackoverflow.com/a/43933889/1013317
*/
private static String queryToSqlString(EntityManager em, Query query) {
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();

// Query with parameters
return databaseQuery.getTranslatedSQLString(session, r);
}

/**
* Overload, see {@link #queryToSqlString(EntityManager, Query)}
*/
private static String queryToSqlString(EntityManager em, String statement) {
return queryToSqlString(em, em.createQuery(statement));
}

/**
* Count the amount of results for a given statement
*/
private static long count(EntityManager em, Query query) {
String countStatement = String.format("SELECT COUNT(*) FROM (%s) AS t", queryToSqlString(em, query));
Query createNativeQuery = em.createNativeQuery(countStatement);
return (long) createNativeQuery.getSingleResult();
}

/**
* Overload, see {@link #count(EntityManager, Query)}
*/
private static long count(EntityManager em, String statement) {
return count(em, em.createQuery(statement));
}

我尝试了几个查询(简单查询、连接查询……),它似乎工作得很好。另外,生成 SQL 字符串时,最终应用于查询对象的 LIMIT 或 OFFSET 将被忽略,因此我什至不需要从生成的语句中删除它。

queryToSqlString 还可以非常方便地记录提交到 DBMS 的 native 语句(如果您不想启用完整的 EclipseLink 日志记录)

关于java - EclipseLink JPQL : Generic COUNT statement for any statement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46804381/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com