2020年7月19日 星期日

使用聚合(Aggregation)函式

本文為【Spring Boot情境式網站開發指南:使用Spring Data JPA、Spring Security、Spring Web Flow】一書的【 第4章 Criteria API入門】延續,完整範例程式碼可至出版社下載

JPQL支援在SELECT敘述內使用AVG、COUNT、MAX、MIN、SUM等聚合函式。

COUNT()

當JPQL使用以下查詢時:
SELECT COUNT(e) FROM Employee e
【語法】
Expression<Long> count(Expression<?> x);
1. 回傳型態為Expression<Long>,即Long型態欄位。
2. 方法參數:
    Expression<?> x:不限定欄位型態。
如以下範例行7:
@Test
public void Criteria_Count() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Long.class);
    Root emp = sql.from(Employee.class);
    sql.select(cb.count(emp));
    TypedQuery typedQuery = em.createQuery(sql);
    Long count = typedQuery.getSingleResult();
    System.out.println(count);
    em.close();
    assertEquals(4, count.intValue());
}

AVG()

當JPQL使用以下查詢時:
SELECT AVG(e.salary) FROM Employee e
對應Criteria API可以使用CriteriaBuilder的avg()方法:
【語法】
<N extends Number> Expression<Double> avg(Expression<N> x);
1. 泛型N必須是Number的子類別,即數字型態。
2. 回傳型態為Expression<Double>,因此數字型態取平均後得到Double型態。
3. 方法參數:
    Expression<N> x:需為數字型態的欄位。
如以下範例行7:
@Test
public void Criteria_Average() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Double.class);
    Root emp = sql.from(Employee.class);
    sql.select(cb.avg(emp.get(Employee_.salary)));
    TypedQuery typedQuery = em.createQuery(sql);
    Double average = typedQuery.getSingleResult();
    System.out.println(average);
    em.close();
    assertEquals(2625.0, average, 0.0);
}

max() & greatest()

當JPQL使用以下查詢取得數字欄位的最大數值時:
SELECT MAX(e.salary) FROM Employee e
對應Criteria API可以使用CriteriaBuilder的max()方法: 
【語法】
<N extends Number> Expression<N> max(Expression<N> x);
1. 泛型N必須是Number的子類別,即數字型態。
2. 回傳型態為Expression<N>,即數字型態欄位。
3. 方法參數:
    Expression<N> x:需為數字型態的欄位。
如以下範例行7:
@Test
public void Criteria_Max() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Double.class);
    Root emp = sql.from(Employee.class);
    sql.select( cb.max( emp.get(Employee_.salary) ) );
    TypedQuery typedQuery = em.createQuery(sql);
    Double max = typedQuery.getSingleResult();
    System.out.println(max);
    em.close();
    assertEquals(4000.0, max, 0.0);
}
相似的情況,但若欄位型態非數字但求最大值,如String和Date,則使用CriteriaBuilder的greatest()方法:
【語法】

<X extends Comparable<? super X>> Expression<X> greatest(Expression<X> x);
1. 泛型X必須有實作Comparable介面,因此可比較。
2. 回傳型態為Expression<X>:型態為X的Expression物件參考,代表實作Comparable介面的物件型態的欄位。
3. 方法參數:
    Expression<X> x:型態為X的Expression物件參考,代表實作Comparable介面的物件型態的欄位。
如以下範例行7:
@Test 
public void Criteria_Greatest() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(String.class);
    Root emp = sql.from(Employee.class);
    sql.select( cb.greatest( emp.get(Employee_.name) ) );
    TypedQuery typedQuery = em.createQuery(sql);
    String greatest = typedQuery.getSingleResult();
    System.out.println(greatest);
    em.close();
    assertEquals("Rose", greatest);
}

min() & least()

當JPQL使用以下查詢取得數字欄位的最小數值時:
SELECT MIN(e.salary) FROM Employee e
對應Criteria API可以使用CriteriaBuilder的min()方法:
【語法】

<N extends Number> Expression<N> min(Expression<N> x);
1. 泛型N必須是Number的子類別,即數字型態。
2. 回傳型態為Expression<N>,即數字型態的欄位。
3. 方法參數:
    Expression<N> x:即數字型態的欄位。
如以下範例行7:
@Test
public void Criteria_Min() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Double.class);
    Root emp = sql.from(Employee.class);
    sql.select( cb.min( emp.get(Employee_.salary) ) );
    TypedQuery typedQuery = em.createQuery(sql);
    Double min = typedQuery.getSingleResult();
    System.out.println(min);
    em.close();
    assertEquals(1500.0, min, 0.0);
}
相似的情況,但若欄位型態非數字但求最小值,如String和Date,則使用CriteriaBuilder的least()方法:
【語法】

<X extends Comparable<? super X>> Expression<X> least(Expression<X> x);
1. 泛型X必須有實作Comparable介面,因此可比較。
2. 回傳型態為Expression<X>:型態為X的Expression物件參考,代表實作Comparable介面的物件型態的欄位。
3. 方法參數:
    Expression<X> x:型態為X的Expression物件參考,代表實作Comparable介面的物件型態的欄位。
如以下範例行7:
@Test
public void Criteria_Least() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(String.class);
    Root emp = sql.from(Employee.class);
    sql.select( cb.least( emp.get(Employee_.name) ) );
    TypedQuery typedQuery = em.createQuery(sql);
    String least = typedQuery.getSingleResult();
    System.out.println(least);
    em.close();
    assertEquals("Denise", least);
}

SUM()

當JPQL使用以下查詢時:
SELECT SUM(e.salary) FROM Employee e
對應Criteria API可以使用CriteriaBuilder的sum()方法:
【語法】

<N extends Number> Expression<N> sum(Expression<N> x);
1. 泛型N必須是Number的子類別,即數字型態。
2. 回傳型態為Expression<N>,即為數字型態的欄位。
3. 方法參數:
    Expression<N> x:需為數字型態的欄位。
如以下範例行7:
@Test
public void Criteria_Sum() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Double.class);
    Root emp = sql.from(Employee.class);
    sql.select(cb.sum(emp.get(Employee_.salary)));
    TypedQuery typedQuery = em.createQuery(sql);
    Double sum = typedQuery.getSingleResult();
    System.out.println(sum);
    em.close();
    assertEquals(10500.0, sum.doubleValue(), 0.0);
}

沒有留言:

張貼留言