Only last record from Custom query - java

The following query return a list but I am only interested in the last element of the list.
#Query("SELECT r FROM Reservation r WHERE r.reservationSeance.id=:seanceId AND r.seanceDate=:seanceDate")
public Reservation findReservationBySeanceDateAndSeanceId(#Param("seanceId") int seanceId, #Param("seanceDate") java.time.LocalDate seanceDate);
How shall I rewrite the SQL-Query in order to implement my idea?

One possible solution is to use ORDER BY r.id DESC :
#Query("SELECT r FROM Reservation r " +
"WHERE r.reservationSeance.id=:seanceId AND r.seanceDate=:seanceDate " +
"ORDER BY r.id DESC")
public Reservation findReservationBySeanceDateAndSeanceId(
#Param("seanceId") int seanceId,
#Param("seanceDate") java.time.LocalDate seanceDate, Pageable pageable);
and because there are no way to use limit in JPQL, you can use Pageable
Pageable pageable = new PageRequest(0, 1);
Reservation reservation = r.findReservationBySeanceDateAndSeanceId(seanceId, seanceDate, pageable);
Another possible solution without Query :
public Reservation findTop1ByReservationSeanceAndSeanceDateOrderByIdDesc(
ReservationSeanceEntity reservationSenace,
java.time.LocalDate seanceDate
)
In this second solution you have to pass the ReservationSeance Object and not the id of ReservationSeance, the query can be read as :
Find top 1 (first one) by `ReservationSeance` and `SeanceDate` order by `Id` Desc order

You need to provide a couple more parameters to your query, especially an ORDER BY clause.
To get the latest seanceId, you'll want to order your results by that id, but in reverse order. Then, just tell the query to return only the first result:
SELECT r FROM Reservation r
WHERE r.reservationSeance.id=:seanceId
AND r.seanceDate=:seanceDate
ORDER BY seanceId
DESC LIMIT 1;

You can try the following, if you are using mysql as your database:
SELECT r
FROM Reservation r
WHERE r.reservationSeance.id=:seanceId
AND r.seanceDate=:seanceDate
order by r.reservationSeance.id desc limit 0,1

Related

JPA native query from list to tuples

I have defined a method on my JPARepository to update a property's entity for a given list of ids.
#Modifying
#Transactional
#Query("UPDATE Entity SET date = ?1 WHERE id IN (?2)")
void updateDeletionDate(Date date, List<Long> ids);
This works, but I've just found out that maximum length of the list is 1000 items (due to ORA-01795), so I'm trying the best approach I've found so far: 2. Use tuples. However, I don't know how to translate the query, since something like this obviously fails: UPDATE Entity SET date = ?1 WHERE (id , 0) IN ((?2, 0))
you could use a join on a subquery which selects the ids you want to update
UPDATE Entity e
SET e.date = ?1
WHERE e.id IN (SELECT i.id FROM (VALUES (?2), (?3), ...) as i(id))

How to write "JPQL" query with "IN" between SELECTs?

I wrote this JPQL query and expect a result as List<Question>:
#Query("SELECT q FROM Question q WHERE q.id IN (SELECT qc.questions FROM QCard qc WHERE qc.id IN (SELECT ct.qCards FROM CTest ct WHERE ct.id=:id))")
These are my classes:
class CTest {
id, List<QCard>
}
class QCard{
id, List<Question>
}
class Question{
id
}
I expected all questions as return for given CTest.id.
But I got a compiler-error with message:
SQLSyntaxErrorException
I tried use ":" before "select" words but it had not helped.
What is wrong?
Test your SQL query in an SQL-client (e.g. Squirrel, DbVisualizer, etc.).
Assuming your foreign keys are named:
question_id in table QCard
card_id in table CTest
you could have an SQL with subselects like:
SELECT q.id
FROM Question q
WHERE q.id IN (
SELECT qc.question_id
FROM QCard qc
WHERE qc.id IN (
SELECT ct.card_id
FROM CTest ct
WHERE ct.id = 1 -- example test id
)
)
Does it return the expected result or are there syntax errors?
Then subsequently replace your subselects by JOINs.
Question and Cards
SELECT q.id, c.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
Cards and Tests
SELECT c.id, t.id
FROM QCard c
JOIN CTest t ON t.card_id = c.id
All together
SELECT q.id, c.id, t.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
JOIN CTest t ON t.card_id = c.id
Note: add WHERE clauses like WHERE t.id = 1 if needed.
Experiment with the FROM/JOIN order as it makes sense.
Then translate the running SQL query to JPQL. For example:
#Query("SELECT q"
+ " FROM CTest test"
// a test has many cards (1:n)
+ " JOIN QCard card ON card.id = test.card_id" // associated cards
// a card has many questions (1:n)
+ " JOIN Question q ON q.id = card.question_id" // associated questions
+ " WHERE test.id = :id")
public List<Question> findQuestionsByTestId(String id);
List<Question> findByIdIn(List<Long> idList); //In repository
or
String qlString = "select i from Item i where i.name IN :names";
Query q = em.createQuery(qlString, Item.class);
List<String> names = Arrays.asList("foo", "bar");
q.setParameter("names", names);
List<Item> actual = q.getResultList();
I did those example in my past work, check it, tnx
In your existing query, in inner queries you are selecting entities and checking IN against Id, which will definitely won't work. As you can't complete entry with the Id.
As you haven't shared your complete entity structure, assuming that you have two way relationship declared correctly in entities, here I am placing a reference query which uses the join:
#Query("SELECT q FROM Question q JOIN q.qCard qc WHERE q.qCardId = qc.id AND qc.cTestId = :id")
Where qCardId is the foreign key reference of QCard entity in Question entity and cTestId is the foreign key reference of CTest entity in QCard entity.
You can use this for your reference to update your query with joins.

Spring Data | Wrong query generation with sorting

I have a very strange problem.
I have some repository method that accepts Pageable as parameter. Here it is:
#Query(value = "SELECT product_name FROM product WHERE number = 1",
countQuery = "SELECT COUNT (id) FROM product",
nativeQuery = true)
public List<String> getAllProducts(Pageable pageable);
When I use this method without sort inside of pageable everything is okay. Hibernate uses next query in this situation: SELECT product_name FROM product WHERE number = 1 limit ?.
But when I use sort inside of Pageable I get such a strange query: SELECT product_name FROM product WHERE number = 1, product_name asc limit ?.
Do you have any suggestions why spring puts comma instead of ORDER BY?

Spring data JPA nativeQuery order by is invalid

The Spring Data Jpa Method like this:
#Query("select pb.id,pp.max_borrow_amt,pp.min_borrow_amt
from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code
where pb.code IN(?1) and pb.status='publish' order by ?2 ",
nativeQuery = true)
List<Object[]> findByCodesIn(List<String> codes,String orderby);
then order by is " max_borrow_amt desc ", but this is invalid.
the List is disordered.
Dynamic sorting in Spring Data JPA
If you used a JPA query you could use Sort as an argument of your query method to define the sorting order:
#Query("select m from Model m")
List<Model> getSortedList(Sort sort);
and then, for example:
List<Model> models = getSortedList(Sort.by(Sort.Direction.DESC, "name"));
But Spring Data JPA can't use Sort with native queries:
Spring Data JPA does not currently support dynamic sorting for native queries, because it would have to manipulate the actual query declared, which it cannot do reliably for native SQL.
However you can use Pageable and its implementation PageRequest instead:
#Query(value = "select m.name as name from models m", nativeQuery = true)
List<ModelProjection> getSortedList(Pageable p);
and then:
List<ModelProjection> modelNames = getSortedList(PageRequest.of(0, 1000, Sort.Direction.DESC, "name"));
P.S. Instead of array of Objects as returned parameters, it's better to use projections, for example:
public interface ModelProjection {
String getName();
}
Note that in this case the good practice is to use aliases in queries (ie m.name as name). They must match with correspondent getters in the projection.
Working demo and test.
Thanks everyone!
My problem has been solved.
If you want to use Spring data jpa nativeQuery & Sort, you should do like this:
#Query(
value ="select pb.id,pp.max_borrow_amt from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code ORDER BY ?#{#pageable} ",
countQuery = "select count(*) from product_loan_basic",
nativeQuery = true
)
Page<Object[]> findAllProductsAndOrderByAndSort(Pageable pageable);
?#{#pageable} is required and countQuery is required.
Pageable pageable = new PageRequest(0,1000,Sort.Direction.DESC,"id");
then the result is sorted.
See Spring Data and Native Query with pagination.

JPQL with subquery to select max count

I'm trying to write a jpql query to select the user with the most comments. If two users have the same number of comments I want to select both.
I tried this, something like this:
SELECT
c.user, COUNT(c.id) as commentCount
FROM
Comment c
WHERE
commentCount = (SELECT MAX(SIZE(user.comments)) FROM User user)
GROUP BY
c.user
and this:
SELECT
c.user
FROM
Comment c
GROUP BY
c.user
HAVING
COUNT(c) = (SELECT MAX(SIZE(user.comments)) FROM User user)
Neither approach works. What do I need to do here?
Here is a solution:
SELECT
u
FROM
User u
WHERE
u.comments.size = (SELECT MAX(u2.comments.size) FROM User u2)
This should work if you are using Oracle:
select u from User u where size(u.comments) = (
select max(count(c.id))
from User u2 inner join u2.comments c
group by u2.id
)
But MySQL and SQL Server do not support nested aggregate functions, max(count(c.id)) in this case. It is suggested to use a subquery, but with HQL you cannot have subqueries in a from clause. So I suggest you do this manually, i.e. load all users:
select u, size(u.comments)
from User u
and loop through the list.
For any others coming here and wanting to select a max(count()) in jpql and doesn't have an array, (like in the question the comments) take following jpql code into consideration:
select e.city
from Employees e
group by e.city
having count(e.id) >= All(select count(e) from Employees e group by e.city)
full example in a JPA Repository:
#Query(value = "select e.city from Employees e group by e.city " +
"having count(e.id) >= All(select count(e) from Employees e group by e.city)")
public List<Cities> findCityByMaxEmployeeCount();

Categories

Resources