2012-04-10 87 views
3

我正嘗試在JPA查詢中使用該組。假設我有一個類Teacher和一個類Student。 A Teacher可以有更多的StudentStudent只能有一個Teacher(一對多)。按JPA和PostgreSQL 9.0分組

以下JPA查詢:

Query q = this.em.createQuery( "SELECT teacher, COUNT(student)" + 
           " FROM StudentJpa student" + 
           " JOIN student.teacher teacher" + 
           " GROUP BY teacher" + 
           " ORDER BY COUNT(student) DESC"); 

生成以下SQL查詢:

select 
     teacherjpa1_.teacher_id as col_0_0_, 
     count(studentjpa0_.id) as col_1_0_, 
     teacherjpa1_.teacher_id as teacher1_0_, 
     teacherjpa1_.name as name0_ 
    from 
     student studentjpa0_ 
    inner join 
     teacher teacherjpa1_ 
      on studentjpa0_.teacher_id=teacherjpa1_.teacher_id 
    group by 
     teacherjpa1_.teacher_id 
    order by 
     count(studentjpa0_.id) DESC 

PostgreSQL的9.0,我得到以下錯誤:

org.postgresql.util.PSQLException: ERROR: column "teacherjpa1_.name" must appear in the GROUP BY clause or be used in an aggregate function

同樣的錯誤沒有按」 t出現在PostgreSQL 9.1中。

任何人都可以解釋我爲什麼嗎? JPA似乎以錯誤的方式生成組:它應該包含所有Teacher屬性,而不僅僅是id。

這是我的JPA /休眠/ DB的配置,如果必要的話:

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:tx="http://www.springframework.org/schema/tx" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 
    <context:property-placeholder location="/WEB-INF/jdbc.properties" /> 

    <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> 
     <constructor-arg> 
      <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
       <property name="driverClassName" value="org.postgresql.Driver" /> 
       <property name="url" value="${db.url}" /> 
       <property name="username" value="${db.username}" /> 
       <property name="password" value="${db.password}" /> 
      </bean> 
     </constructor-arg> 
    </bean> 

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
     <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" /> 
     <property name="showSql" value="${db.showSql}" /> 
     <property name="generateDdl" value="${db.generateDdl}" /> 
    </bean> 

    <!-- enabling annotation driven configuration /--> 
    <context:annotation-config /> 
    <context:component-scan base-package="my.package" /> 

    <!-- Instructs the container to look for beans with @Transactional and decorate them --> 
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> 

    <!-- FactoryBean that creates the EntityManagerFactory --> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="jpaVendorAdapter" ref="jpaAdapter" /> 
     <property name="jpaProperties"> 
      <props> 
       <prop key="hibernate.format_sql">true</prop> 
       <prop key="hibernate.hbm2ddl.auto">update</prop> 
      </props> 
     </property> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <!-- A transaction manager for working with JPA EntityManagerFactories --> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 
</beans> 

謝謝!

更新 - 解決方案是指定GROUP BY teacher.id, teacher.name而不是GROUP BY teacher,但這並不方便。有更好的解決方案嗎?

+0

這是PostgreSQL 9.0中最簡單的解決方案。您也可以使用CTE來處理GROUP BY,並在引入其他列的SELECT中引用CTE,但這並不簡單。也許你可以像Heroku一樣提供最新的產品發佈,提及你爲什麼需要它? – kgrittn 2012-04-10 17:25:34

+0

CTE是一個解決方案,但它仍然不理想。我知道在使用專用數據庫時,您可以在Heroku上升級到9.1。目前我使用的是共享的,所以我想這可能是他們升級到9.1的問題......無論如何我都會聯繫他們!謝謝 – satoshi 2012-04-10 18:17:55

回答

5

該查詢在PostgreSQL版本9.1中變得有效。看起來你在本地使用的是PostgreSQL 9.1版本,而Heroku使用的是更早的版本。

見9.1版本說明:

http://www.postgresql.org/docs/9.1/interactive/release-9-1.html

在該頁面上,根據查詢部分,它說:

Allow non-GROUP BY columns in the query target list when the primary key is specified in the GROUP BY clause (Peter Eisentraut)

The SQL standard allows this behavior, and because of the primary key, the result is unambiguous.

爲了得到這個在早期版本的PostgreSQL添加工作所有表達式從選擇列表中不使用聚合函數到GROUP BY子句。

+0

謝謝,這完美地解釋了爲什麼它不適用於Heroku。實際上Heroku仍然使用9.0版本。 但是,爲什麼JPA沒有指定所有'Teacher'屬性而僅僅是ID來生成組?或者我如何更改代碼以使其在PostgreSQL 9.0上運行?謝謝。 – satoshi 2012-04-10 16:34:48

+0

我編輯了答案,以解釋您可以通過將所有非聚合表達式添加到GROUP BY子句來解決此問題。 – kgrittn 2012-04-10 17:22:26

+0

謝謝@ kilrittn。顯然這個解決方案並不理想,但如果它是唯一一個我將這個答案標記爲接受!讓我們等待另一個解決方案,如果有的話...謝謝 – satoshi 2012-04-10 18:16:37