带有count和group by的JPA Query(与join表的多对多关系)

时间:2011-12-01 22:00:02

标签: jpa count group-by many-to-many

我有点问题。在我的应用程序中,我有两个实体,看起来像片段:

//imports, annotations, named queries
public class WishList implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "wishes_seq", 
                       sequenceName = "wish_list_id_seq", 
                       allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "wishes_seq")
    @Basic(optional = false)
    @NotNull
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 80)
    @Column(name = "book_title")
    private String bookTitle;

    @Size(max = 80)
    @Column(name = "book_cattegory")
    private String bookCattegory;


    @ManyToMany(cascade= CascadeType.ALL, fetch= FetchType.EAGER)
    @JoinTable(name="wl_authors", 
               joinColumns={@JoinColumn(name="wl_id")},
               inverseJoinColumns={@JoinColumn(name="author_id")})
    private List<Author> authorList; 

    // other methods

和第二个:

//imports, annotations, named queries    
public class Author implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name = "authors_seq", 
                       sequenceName = "authors_id_seq", 
                       allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, 
                    generator = "authors_seq")
    @Basic(optional = false)
    @NotNull
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 58)
    @Column(name = "author_name")
    private String authorName;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 58)
    @Column(name = "author_surname")
    private String authorSurname;

    @Size(max = 58)
    @Column(name = "nationality")
    private String nationality;

    @Size(max = 64)
    @Column(name = "birth_place")
    private String birthPlace;

    @JoinTable(name = "wl_authors", 
               joinColumns = {@JoinColumn(name = "author_id",
                                          referencedColumnName = "id")},
               inverseJoinColumns = {@JoinColumn(name = "wl_id",
                                                 referencedColumnName = "id")})
    @ManyToMany(fetch = FetchType.EAGER)
    private List<WishList> wishListList;

    // other methods

正如您可以看到我准备的实体代表数据库中的两个表,它们处于多对多的关系中(我使用了连接表)。我想计算WishList实体中的所有结果,它们具有相同的作者,标题和cattegory,并返回所有结果如下:

  1. 计算结果
  2. 书名
  3. book cattegory
  4. 书籍作者
  5. 结果应按计数结果排序。 我准备的JPA查询:

    SELECT Count(wl.bookTitle) AS POP, 
           wl.bookTitle, 
           wl.bookCattegory 
    FROM WishList wl 
    GROUP BY wl.bookTitle, 
             wl.bookCattegory, 
             wl.authorList 
    ORDER BY POP DESC  
    

    不满足我。我不能从愿望清单中找回这本书的作者。当我在&#39; FROM&#39;之前放置wl.authorList时出现EJB异常:

    ...
    Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: org.postgresql.util.PSQLException: ERROR: column "t1.id" must appear in the GROUP BY clause or be used in an aggregate function
    ...
    Call: SELECT COUNT(t0.book_title), t0.book_title, t0.book_cattegory, t1.id, t1.author_name, t1.author_surname, t1.birth_place, t1.nationality FROM wl_authors t4, wl_authors t3, authors t2, authors t1, wish_list t0 WHERE (((t3.wl_id = t0.id) AND (t1.id = t3.author_id)) AND ((t4.wl_id = t0.id) AND (t2.id = t4.author_id))) GROUP BY t0.book_title, t0.book_cattegory, t2.id, t2.author_name, t2.author_surname, t2.birth_place, t2.nationality ORDER BY COUNT(t0.book_title) DESC
    Query: ReportQuery(referenceClass=WishList sql="SELECT COUNT(t0.book_title), t0.book_title, t0.book_cattegory, t1.id, t1.author_name, t1.author_surname, t1.birth_place, t1.nationality FROM wl_authors t4, wl_authors t3, authors t2, authors t1, wish_list t0 WHERE (((t3.wl_id = t0.id) AND (t1.id = t3.author_id)) AND ((t4.wl_id = t0.id) AND (t2.id = t4.author_id))) GROUP BY t0.book_title, t0.book_cattegory, t2.id, t2.author_name, t2.author_surname, t2.birth_place, t2.nationality ORDER BY COUNT(t0.book_title) DESC")
    Caused by: org.postgresql.util.PSQLException: ERROR: column "t1.id" must appear in the GROUP BY clause or be used in an aggregate function
    ...
    

    有人可以帮我创建apriopriate查询吗?是否可以在单个查询中执行此操作?

3 个答案:

答案 0 :(得分:0)

我认为您无法使用一个JPQL查询来实现它。也许,如果使用本机查询,你可能会实现它(不确定,那)。

考虑将问题分成两部分:

  • 调用一个返回统计信息但没有作者的查询
  • 对于每个返回的行,获取作者。

首先调用这样的查询:

SELECT DISTINCT COUNT(wl.bookTitle) AS POP, 
                wl.bookTitle, 
                wl.bookCattegory, 
                MAX(wl.id) 
FROM WishList wl 
GROUP BY wl.bookTitle, wl.bookCattegory, wl.authorList 
ORDER BY POP DESC

根据查询,每个返回的行将具有相同的作者。 MAX(wl.id)仅用于获取您可以查询作者列表的其中一个ID。

拥有这个id你可以为每个记录取得作者并返回这些准备好的数据(人气,书名,类别,作者)。

在一个查询中,它肯定不会在性能类别中获得最高排名,此时我还没有看到其他解决方案。

顺便说一句 - 你确定你的模型还行吗?每个WishList只有一个书名,类别和作者?书籍数据是否应该与Book实体分开,而每个WishList都包含许多Books?我认为应该更容易查询包含相同书籍的WishLists

答案 1 :(得分:0)

我认为你不能用ManyToMany分组,

试,

SELECT Count(wl.bookTitle) AS POP, wl.bookTitle,  wl.bookCattegory, a.id FROM WishList wl join wl.authorList a GROUP BY wl.bookTitle, wl.bookCattegory, a.id ORDER BY POP DESC

答案 2 :(得分:0)

我知道它有点晚了,但查询是否适用于其他数据库,如MySQL?

Postgres有一个限制,并且在选择部分中出现的所有列中逐段强制执行 - 确切地说错误是什么。

v9.1开始,此错误不应再发生了:

在GROUP BY子句中指定主键时,在查询目标列表中允许非GROUP BY列[...] SQL标准允许此行为,并且由于主键,结果为毫不含糊的。