如何在JPA Repository中编写带INNER JOIN子查询的查询语句
问题根因
HQL(JPQL)语法本身不支持在INNER JOIN后直接嵌套子查询,你当前的@Query默认使用HQL解析模式,因此会抛出括号位置的语法错误。
解决方案
方案1:使用原生SQL查询(推荐,改动最小)
直接在@Query注解中开启原生SQL模式,沿用你已经写好的原生SQL逻辑即可,同时建议把硬编码的线程ID、接收者ID改成参数化写法,提升复用性:
@Repository public interface RecipientJpaRepository extends JpaRepository<RecipientModel, Long> { @Query( value = "SELECT 1 " + "FROM recipient r " + "INNER JOIN ( " + " SELECT m.id, MAX(m.created_at) " + " FROM message m INNER JOIN thread t " + " ON t.id = m.thread_id " + " WHERE t.id = :threadId " + ") th " + "ON th.id = r.message_id " + "WHERE r.recipient_id = :recipientId ", nativeQuery = true ) Integer isRecipientOfThread(@Param("threadId") Long threadId, @Param("recipientId") Long recipientId); }
注意:原生SQL用的是数据库表名、字段名,不是实体类名和实体属性名,要和你的数据库实际命名对应。如果查询不到符合条件的记录会返回null,建议返回类型用包装类Integer避免拆箱空指针。
方案2:改写HQL逻辑,把子查询放到WHERE条件中
如果不想用原生SQL,可以调整查询逻辑,将子查询移到WHERE条件里,HQL支持WHERE后的子查询:
@Repository public interface RecipientJpaRepository extends JpaRepository<RecipientModel, Long> { @Query("SELECT 1 FROM RecipientModel r " + "WHERE r.recipientId = :recipientId " + "AND r.messageId = (" + " SELECT m.id FROM MessageModel m " + " WHERE m.threadId = :threadId " + " ORDER BY m.createdAt DESC " + " LIMIT 1" + ")") Integer isRecipientOfThread(@Param("threadId") Long threadId, @Param("recipientId") Long recipientId); }
这个写法的逻辑和你原来的SQL完全等价,都是判断接收者是否是指定线程最新一条消息的接收者。
内容的提问来源于stack exchange,提问作者s1n7ax
相关产品推荐
相关产品推荐

