Prune table to 500 records in JPQL

adrianus :

I work on some kind of cache and from time to time, we need to prune the table to 500 records, based on a last_access_date (only keep the 500 recently accessed rows).

With "plain" SQL, this could be done with:

DELETE FROM records WHERE id not in 
    (SELECT id FROM records ORDER BY last_access_date DESC LIMIT 500)

Now as there is no LIMIT or something like ROWNUM in JPQL, the only solution I found was in native SQL, which is suboptimal, because we run on multiple DBMS (at least Oracle and MSSQL).

Also, setMaxResults() (JPQLs version of LIMIT) doesn't seem valid for DELETE statements.

Is there really no way to to this with JPQL?

Ayrton :

You could do this:

String sql = "SELECT x.id FROM records x ORDER BY x.last_access_date DESC";
TypedQuery<Long> query = em.createQuery(sql, Long.class);

List<Long> ids = query.setMaxResults(500).getResultList();

String delete = "DELETE FROM records x where x.id not in :ids";
em.createQuery(delete).setParameter("ids", ids).executeUpdate();

I don't recall the exact syntax for the delete query, so you may have to put the :ids between parenthesis, like:

String delete = "DELETE FROM records x where x.id not in (:ids)";

Edit: dkb proposed a faster solution on the comments (depends on unique dates for perfect accuracy on the amount of remaining rows):

String sql = "SELECT x.last_access_date FROM records x ORDER BY x.last_access_date DESC";

//If you're not using calendar, change to your specific date class
TypedQuery<Calendar> query = em.createQuery(sql, Calendar.class);

Calendar lastDate = query.setFirstResult(499).setMaxResults(1).getSingleResult();

String delete = "DELETE FROM records x where x.last_access_date < :lastDate";
em.createQuery(delete).setParameter("lastDate", lastDate, TemporalType.DATE).executeUpdate();

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=69512&siteId=1