如何使用 Spring Data 解决 JPA 查询中 DISTINCT 的 ORDER BY 子句错误?

问题描述 投票:0回答:1

我正在 Spring 数据存储库中使用 JPA 查询,该查询使用 DISTINCTORDER BY 子句 获取数据。该查询在没有 DISTINCT 的情况下工作,但添加它会导致以下错误

Expression #1 of ORDER BY clause is not in SELECT list, references column 'entityName.auditTimestamp' which is not in SELECT list; this is incompatible with DISTINCT

这是我正在使用的查询:

@Query("SELECT DISTINCT new com.example.dto.MyDTO(entity.id, user.id, user.email, role.displayValue, practice.id, practice.name, entity.inactiveDate, entity.type, entity.status, entity.documentId) "
     + "FROM Entity entity "
     + "LEFT JOIN User user ON entity.userId = user.id "
......
     + "ORDER BY entity.auditTimestamp DESC")

处理这种情况的最佳方法是什么?

  • 有没有办法保持 DISTINCT 和 ORDER BYEntity.auditTimestamp 而不在 SELECT 列表中包含auditTimestamp?或者是否有其他方法可以在 JPA 中实现相同的结果?
sql mysql spring-boot jpa
1个回答
0
投票

出现此错误的原因是,在使用 DISTINCT 时,SQL 要求 ORDER BY 子句中的列也位于 SELECT 列表中。当应用 DISTINCT 时,数据库会对投影中选择的字段进行排序,但实体.auditTimestamp 不包含在 SELECT 列表中,从而导致错误。

以下是解决此问题的一些方法:

  1. 在选择列表中包含auditTimestamp 您可以将entity.auditTimestamp 添加到MyDTO 构造函数内的SELECT 列表。这样,它就可用于 ORDER BY 子句。但是,如果您不希望auditTimestamp成为MyDTO的一部分,您可以考虑修改MyDTO以忽略或单独处理它。
@Query("SELECT DISTINCT new com.example.dto.MyDTO(entity.id, user.id, user.email, role.displayValue, practice.id, practice.name, entity.inactiveDate, entity.type, entity.status, entity.documentId, entity.auditTimestamp) "
     + "FROM Entity entity "
     + "LEFT JOIN User user ON entity.userId = user.id "
     + "ORDER BY entity.auditTimestamp DESC")
  1. 使用子查询

另一种方法是使用子查询。首先,根据所需字段获取不同的 ID,然后在主查询中按auditTimestamp 对结果进行排序。这是一个例子:

@Query("SELECT new com.example.dto.MyDTO(e.id, u.id, u.email, r.displayValue, p.id, p.name, e.inactiveDate, e.type, e.status, e.documentId) "
     + "FROM Entity e "
     + "LEFT JOIN User u ON e.userId = u.id "
     + "WHERE e.id IN (SELECT DISTINCT entity.id FROM Entity entity) "
     + "ORDER BY e.auditTimestamp DESC")

这可能需要根据您的实体结构调整查询,但它可以允许您在订购时保留 DISTINCT 逻辑。

  1. 在 Java 中获取不同的结果 使用 ORDER BY 获取不不同的结果,然后消除 Java 中的重复项。如果有很多行,这可能效率较低,但对于较小的数据集来说它可以很好地工作。
@Query("SELECT new com.example.dto.MyDTO(entity.id, user.id, user.email, role.displayValue, practice.id, practice.name, entity.inactiveDate, entity.type, entity.status, entity.documentId) "
     + "FROM Entity entity "
     + "LEFT JOIN User user ON entity.userId = user.id "
     + "ORDER BY entity.auditTimestamp DESC")
List<MyDTO> results = repository.findAll();
List<MyDTO> distinctResults = results.stream().distinct().collect(Collectors.toList());
© www.soinside.com 2019 - 2024. All rights reserved.