0

I want to select rows that have a distinct email, see the example table below:

+----+---------+-------------------+-------------+
| id | title   | email             | commentname |
+----+---------+-------------------+-------------+
|  3 | test    | rob@hotmail.com   | rob         |
|  4 | i agree | rob@hotmail.com   | rob         |
|  5 | its ok  | rob@hotmail.com   | rob         |
|  6 | hey     | rob@hotmail.com   | rob         |
|  7 | nice!   | simon@hotmail.com | simon       |
|  8 | yeah    | john@hotmail.com  | john        |
+----+---------+-------------------+-------------+

The desired result would be:

+----+-------+-------------------+-------------+
| id | title | email             | commentname |
+----+-------+-------------------+-------------+
|  3 | test  | rob@hotmail.com   | rob         |
|  7 | nice! | simon@hotmail.com | simon       |
|  8 | yeah  | john@hotmail.com  | john        |
+----+-------+-------------------+-------------+

Where I don't care which id column value is returned. What JPA Specification can be used for this?

Here is the specification class,

public class UserSearchSpecification implements Specification<UserSearch> {

    private static final Logger LOGGER = LogManager.getLogger(UserSearchSpecification.class);

    private static final long serialVersionUID = 1L;
    private List<SearchCriteria> list;

    /**
     * Custom JPA Specification Constructor
     * 
     */
    public UserSearchSpecification() {
        this.list = new ArrayList<>();
    }

    public void add(SearchCriteria criteria) {
        list.add(criteria);
    }

    @Override
    public Predicate toPredicate(Root<UserSearch> root, CriteriaQuery<?> arg1, CriteriaBuilder builder) {
         //create a new predicate list
        List<Predicate> predicates = new ArrayList<>();

        //add add criteria to predicates
        for (SearchCriteria criteria : list) {
            if (criteria.getOperation() == (SearchOperation.GREATER_THAN)) {
                predicates.add(builder.greaterThan(
                        root.get(criteria.getKey()), criteria.getValue().toString()));
            } else if (criteria.getOperation() == (SearchOperation.LESS_THAN)) {
                predicates.add(builder.lessThan(
                        root.get(criteria.getKey()), criteria.getValue().toString()));
            } else if (criteria.getOperation() == (SearchOperation.GREATER_THAN_EQUAL)) {
                predicates.add(builder.greaterThanOrEqualTo(
                        root.get(criteria.getKey()), criteria.getValue().toString()));
            } 
        }

        return builder.and(predicates.toArray(new Predicate[0]));
    }

}
Meet Patel
  • 59
  • 2
  • 12

1 Answers1

0

I hate JPAs Criteria API to much to produce actual code, but the basic idea is that you create the following construct:

from MyEntity e 
where e.id in (
    select min(id) 
    from MyEntity e2 
    where e.email = e2.email
)

This should be expressible with the Criteria API and therefore with Spring Data JPA Specifications.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348