【问题标题】:Translate this MySQL query to JPQL将此 MySQL 查询转换为 JPQL
【发布时间】:2014-01-17 19:34:50
【问题描述】:

我不确定这个 MySQL 查询在 JPQL 中的外观如何。 详情:

select title
from post
order by (
  select count(postId)
  from comment
  where comment.postId=post.id
) desc;

编辑: 后表外观:

mysql> desc post;
+---------------+----------------+------+-----+---------+----------------+
| Field         | Type           | Null | Key | Default | Extra          |
+---------------+----------------+------+-----+---------+----------------+
| post_id       | int(11)        | NO   | PRI | NULL    | auto_increment |
| post_content  | varchar(50000) | NO   |     | NULL    |                |
| post_date     | datetime       | NO   |     | NULL    |                |
| post_summary  | varchar(1000)  | YES  |     | NULL    |                |
| post_title    | varchar(300)   | NO   |     | NULL    |                |
| post_visitors | int(11)        | NO   |     | NULL    |                |
| user_id       | int(11)        | NO   | MUL | NULL    |                |
| category_id   | int(11)        | NO   | MUL | NULL    |                |
+---------------+----------------+------+-----+---------+----------------+

评论表外观:

mysql> desc comment;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| comment_id      | int(11)      | NO   | PRI | NULL    | auto_increment |
| comment_content | varchar(600) | NO   |     | NULL    |                |
| comment_date    | datetime     | NO   |     | NULL    |                |
| comment_title   | varchar(300) | NO   |     | NULL    |                |
| user_id         | int(11)      | NO   | MUL | NULL    |                |
| post_id         | int(11)      | NO   | MUL | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

这是mysql,终端中的命令。

mysql> select post_title from post order by (select count(post_id) from comment where comment.post_id=post.post_id) desc;

我试过了,但它不起作用:

SELECT p FROM Post p ORDER BY 
(SELECT c COUNT(c.getPost().getId()) 
from Comment c 
where c.getPost().getId()=p.getId()) 
desc

【问题讨论】:

  • 我正在尝试获取按 cmets 计数排序的帖子。评论最多的帖子在前。
  • 我没有使用 JPQL,但是从文档来看它看起来很像普通的 SQL。在 docs.oracle.com 的任何示例中,我都没有看到像 getPost() 这样的方法调用。不能正常访问列吗?
  • @Barmar 嗯,这些表是用 JPA 映射到 mysql 数据库的。因此,getXXX() 是相应类中的 getter 方法。这实际上是 NamedQuery 注解的查询参数中的内容。
  • 据我所知,JPQL 负责映射,您使用普通的table.column 语法编写查询。我怀疑您所要做的就是将查询重写为普通连接,而不是在 ORDER BY 子句中使用相关子查询。我会在答案中显示我的建议。

标签: mysql jpql


【解决方案1】:

非工作方法的主要问题是从 JPQL 查询调用 Java 类的方法 - 预计不会工作。

假设实体的重要属性大致如下:

@Entity
public class Post {
    @Id int id;
    @OneToMany (mappedBy = "post") List<Comment> comments;
    //...
}

@Entity
public class Comment {
    @Id int id;
    @ManyToOne Post post;
    //...
}

那么下面的 Hibernate+MySQL 组合就足够了:

SELECT p 
FROM Post p 
ORDER BY SIZE(p.comments) DESC

JPA 2.0 规范需要更复杂的查询,因为可以在 ORDER BY 子句中使用的内容相当有限:

  1. state_field_path_expression 计算为指定实体或可嵌入类抽象模式类型的可排序状态字段 在 SELECT 子句中由以下之一: • a general_identification_variable • a 单值对象路径表达式
  2. 一个 state_field_path_expression 计算为相同实体或可嵌入抽象模式类型的相同状态字段作为 SELECT 子句中的 state_field_path_expression
  3. 一个result_variable,它指的是SELECT 子句中指定了相同result_variable 的可订购项。这可能 是聚合表达式、标量表达式或 SELECT 子句中的 state_field_path_expression。

以下查询也应与其他实现一起使用。附加变量是结果的一部分当然有点乏味:

SELECT p, SIZE(p.comments) as ord  
FROM Post p 
ORDER BY ord DESC

【讨论】:

  • 是的,这种方式的结果不是我真正需要的“干净”Post 对象列表。反正我还没有找到在JPQL中表达这个查询的方法,所以我使用了native SQL。这是创建查询Query q = em.createNativeQuery("select * from post order by (select count(post_id) from comment where comment.post_id=post.post_id) desc", Post.class); 的代码摘录
  • 一个多星期后,我再次面临同样的问题。我意识到我不能使用本机查询,因为它只返回实体Post(post 表列) 的属性。即使结果是按帖子数量排序的 cmets,我在结果中也看不到那个数字。与此同时,我了解到这种查询应该使用JPA Criteria API 创建。你可能熟悉JPA Criteria API 吗?对SELECT p FROM Post p ORDER BY SIZE(p.comments) DESC 的常见JPA 条件查询应该如何?
  • 没有意识到(目前)我已经面临这个问题,我在这里问了另一个问题:stackoverflow.com/questions/20981160/…。你可以在那里看到实体类代码,尽管它与你的代码相似在你的答案中假设。
【解决方案2】:

我不使用 JPQL,但也许这会起作用(你也可以在 MySQL 中使用它):

SELECT post_title, COUNT(c.post_id) AS c
FROM Post p
LEFT JOIN Comment c
ON p.post_id = c.post_id
ORDER BY c

【讨论】:

  • 嗯,尝试了你的普通 SQL 方法,不起作用,出现异常:org.apache.openjpa.persistence.ArgumentException: "Encountered "COUNT ( *" at character 20 .....(我也是 JPQL 的新手)
  • 嗯,可能是不允许COUNT(*),试试更新
  • @Bramar 现在,得到异常 org.apache.openjpa.persistence.ArgumentException: "Encountered "LEFT JOIN Comment c" at character 54 ...
  • 不知道为什么,我在docs.oracle.com/html/E24396_01/ejb3_langref.html的文档中看到了LEFT JOIN
  • @Bramar 引用 JPQL 章节:JPQL 提供调用本机 SQL 查询的能力。 所以,我想,本机 sql 应该可以工作,不知道为什么不能工作。
【解决方案3】:

我使用原生 SQL 来获得我需要的结果。所以,这并不是我的问题的真正答案,但我会发布我所做的以及有效的方法(使用普通的SQL)。 因为,它不是用JPQL实现的,所以entity class中没有named query,而是使用了native query(在DAO object的方法内)。

所以,这是方法内容:

public List<Post> getMostCommentedPosts(){
    Query q = em.createNativeQuery("select * from post order by "
            + "(select count(post_id) from comment where comment.post_id=post.post_id) desc", Post.class);
    List<Post> resultList = (List<Post>) q.getResultList();

    if (resultList.isEmpty())
        return null;
    else
        return resultList;
}

【讨论】:

    猜你喜欢
    • 2021-10-09
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 2016-07-06
    • 2011-07-05
    • 2011-09-29
    • 2020-10-05
    • 1970-01-01
    相关资源
    最近更新 更多