簡體   English   中英

EclipseLink JPQL:任何語句的通用COUNT語句

[英]EclipseLink JPQL: Generic COUNT statement for any statement

我有一個應用程序,它可以用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)

即使似乎支持子選擇, cannot be the first declaration of the FROM clause. 錯誤很明顯。

難道我做錯了什么?

我的最終目標是嘗試有一個標准的COUNT查詢,我可以將其用於任何類型的語句,只需使用COUNT(*) FROM (..statement..) ,這樣實現非常通用。

或者,如果有可以實現相同目標的方法,則也很有用。


編輯

還嘗試COUNT(0)' as suggested, like this:使用COUNT(0)' as suggested, like this: 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的本機語句(如果您不想啟用完整的EclipseLink記錄)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM