2012-04-10 43 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