如何编写JPQL查询以从两个表中选择数据,这些表从第一个表返回完整的记录集

时间:2019-05-22 15:50:40

标签: spring-data-jpa jpql

我正在处理带有JPA的Spring-Boot应用程序以及Postgres中的数据库。

当前目标是从一个表中检索条目以及从另一个表中检索一些汇总统计信息。

在传统SQL中,我将使用语句 LEFT JOIN(子查询),如下所示:

SELECT d.*, stats.avg_salary
FROM departments d
LEFT JOIN
  (SELECT e.dep_id, avg(e.salary) AS avg_salary
  FROM employees e
  GROUP BY e.dep_id) stats
ON (d.id = stats.dep_id)

现在我在JPQL中需要类似的东西。

重点是检索所有部门,包括那些薪水为NULL的员工或根本没有员工的部门。

到目前为止,我创建的查询(请参见下文)仅返回具有匹配项的部门(其工作方式类似于 INNER JOIN ),但我需要它还包括平均薪水为NULL的条目

@Query("SELECT d, avg(e.salary) "
  +"FROM Department d, Employee e "
  +"WHERE (e.department = d) "
  +"GROUP BY d")
public List<Tuple> getDepartmentsStats();

在JPQL中编写这种查询的最优雅的方法是什么?

1 个答案:

答案 0 :(得分:0)

您可以使用本机查询

  @Query(value =
    "SELECT d.name, stats.avg_salary " + 
    "FROM department d " + 
    "LEFT JOIN " + 
    "  (SELECT e.department_id, avg(e.salary) AS avg_salary " + 
    "  FROM employee e " + 
    "  GROUP BY e.department_id) stats " + 
    "ON (d.id = stats.department_id)", nativeQuery = true
    )
  public List<Tuple> getNativeDepartmentsStats();

并且如果DepartmentEmployee有密切的关系,例如

@Entity
class Department {
  @Id @GeneratedValue
  Long id;
  String name;
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "department")
  Set<Employee> employees;
...

那么您可以使用纯JPQL之类的

  @Query("SELECT d , avg(e.salary) FROM Department d left join d.employees e GROUP BY d")
  public List<Tuple> getFullDepartmentsStats();

可能更好的解决方案是使用

之类的Projection
interface DepAvg {
  Department getDepartment();
  Long getAverage();
}

然后您可以使用类似的

  @Query(value =
      "SELECT dep.name Department, stats.Average Average " + 
      "FROM department dep " + 
      "LEFT JOIN " + 
      "  (SELECT e.department_id, avg(e.salary) AS Average " + 
      "  FROM employee e " + 
      "  GROUP BY e.department_id) stats " + 
      "ON (dep.id = stats.department_id)", nativeQuery = true
      )
    public List<DepAvg> getDepartmentsAvg();