We can add expressions to the having clause when we use Dynamic formula, @Aggregation properties or RawSql.


Dynamic formula

See here for more details on dynamic aggregation formula (sum, min, max, count, avg).

// e.g. sum(hours)

List<DMachineStats> result =
  new QDMachineStats()
  .select("date, sum(totalKms), sum(hours)")
    .gt("sum(hours)", 2)                         // (1) having clause
select t0.date, sum(t0.total_kms), sum(t0.hours)
from d_machine_stats t0
group by t0.date
having sum(t0.hours) > ?                        -- (1) having clause



With @Aggration and @Sum properties these are properties on the query bean so we just use them as normal but after having().

@Table(name = "orders")
public class Order extends BaseModel {


  LocalDate orderDate;

  @Aggregation("max(orderDate)")     // aggregation property
  LocalDate maxOrderDate;

  @Aggregation("count(*)")           // aggregation property
  Long totalCount;

So we can use maxOrderDate and totalCount properties like other query bean properties. Add predicates on these aggregation properties to the having clause like:

List<Order> orders = new QOrder()
  .select(o.status, o.maxOrderDate, o.totalCount)
  .status.notEqualTo(Order.Status.COMPLETE)             // (1) where clause - non aggregate properties
  .totalCount.greaterThan(1)                            // (2) having clause - aggregate properties
select t0.status, max(t0.order_date), count(*)
from orders t0
where t0.status <> ?                                    // (1)
group by t0.status
having count(*) > ?                                     // (2)



With parsed RawSql we can also add expressions to the having clause.

String sql =
  "select order_id, count(*) as totalItems, sum(order_qty*unit_price) as totalAmount \n" +
    "from o_order_detail \n" +
    "group by order_id";

RawSql rawSql = RawSqlBuilder.parse(sql).columnMapping("order_id", "order.id").create();

List<OrderAggregate> l2 = DB.find(OrderAggregate.class)
    .gt("order.id", 0)
  .having()                                           // having clause
    .lt("totalItems", 3)
    .gt("totalAmount", 50)