So my problem is the following:
I have a table I want a filter to apply to. This filter should call a query which finds based on the given information the reports.
This is how my query looks:
#Query("SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE + '%' COALESCE(query,'%') + '%'")
List<Report> getReportsByAppliedFilter(#Param("importance") int importance, #Param("source") String source,
#Param("resolvedStatus") int resolvedStatus, #Param("query") String query);
Problem is: IntelliJ does not like the following:
LIKE + '%' COALESCE(query,'%') + '%'
Error: expected, got +
Do you have any idea how to solve this otherwise?
Yeah, time to go to bed. You dont use + for concat , you use concat():
#Query(value = "SELECT r FROM Report r WHERE r.importanceLevel = COALESCE(importance,'%')" +
"AND r.source = COALESCE(source,'%')" +
"AND r.resolvedStatus = COALESCE(resolvedStatus,'%')" +
"AND r.header LIKE CONCAT('%', COALESCE(query,'%'), '%')")
If your column name is request_status and table name is connections then use COALESCE like
#Query(value = "SELECT connections.id, COALESCE(connections.request_status,'') as request_status.... ", nativeQuery = true)
List<ZXYType> xysfunction();
Here if request_status is null then it will be replaced by an empty string.
Related
It is necessary to select dataset using JPQL query with optional condition - comparing the field value (LocalDateTime type) with a user-specified parameter (also LocalDateTime type).
First I made a well working code:
return entityManager.createQuery(
"SELECT new com.******.*******.*******.****.models.dto.SomeDto " +
"(s.id, " +
"s.userId) " +
"s.persistDate) " +
"FROM Some s WHERE s.userId = :userId
AND s.persistDate >= :userDateTime", SomeDTO.class)
.setParameter("userId", userId)
.setParameter("userDateTime", userDateTime)
This code works but there is one problem:
this condition may exist or may not exist - dependent on app logic. Therefore, there is a need not to use injection using .setParameter (for this condition), but to form a string (which may be empty) depending on the logic and then add to the request:
String extraCondition = (userDateString.equals("false")) ? "" :
"AND s.persistDateTime >= " + userDateString;
return entityManager.createQuery(
"SELECT new com.******.*******.*******.****.models.dto.SomeDto " +
"(s.id, " +
"s.userId) " +
"s.persistDate) " +
"FROM Some s WHERE s.userId = :userId " + extraCondition, SomeDTO.class)
.setParameter("userId", userId)
But the problem is that no matter how I tried to format the userDateString variable, I get an Internal Server Error.I even tried using just a text string instead of variable (tried with different formatting):
String extraCondition = (userDateString.equals("false")) ? "" :
"AND s.persistDateTime >= 2023-01-27T23:30:50";
But the result is also bad - Internal Server Error.
I also tried using the .isAfter method instead of the ">=" operator, but that didn't help either.
How to inject LocalDateTime values comparing into query as String?
even if the date string may or may not be necesssary, you can (and should!) still use parameter injection, not formatted values.
Basically, your code should look like this:
String queryStr = ....;
boolean someCondition = <expensive_test_here>;
if(someCondition) {
queryStr += " AND s.persistDate >= :userDateTime";
}
Query q = em.createQuery(queryStr).setParameter("userId", userId);
if(someCondition) {
q.setParameter("userDateTime", userDateTime);
}
#Query(value =
"SELECT * " +
"WHERE (type REGEXP ?1) " +
"AND status= ?2 " +
"AND date(createdAt)..." +
"ORDER BY id DESC " +
"LIMIT ?4",
nativeQuery = true)
Optional<List<Item>> findLatest(String type, String status, String date, int limit);
I have this query where I'd like to filter by createdAt, only if the date value from the parameter is not null.
If String date = null, the query should not consider the AND date(createdAt)...
However if String date = "today" the query should include something like AND date(createdAt) = CURRENT_DATE
How can I achieve this?
Simplified you can make
If you have more choice you need case when
The idea is when the condition is not met, we let the and part always be true
so that the where calsue is true if all the other conditions are met
SELECT * FROM
A
WHERE
status= 72
AND IF( date = "today" , date(createdAt), current_date) = current_date
The way we usually handle this is by adding a logical check to the WHERE clause which allows a null date.
#Query(value = "SELECT * " +
// ...
"WHERE (type REGEXP ?1) AND " +
" status = ?2 AND " +
" (DATE(createdAt) = ?3 OR ?3 IS NULL) " +
"ORDER BY id DESC " +
nativeQuery = true)
Optional<List<Item>> findLatest(String type, String status, String date);
Note that it is not possible to bind parameters to the LIMIT clause, therefore I have removed it. Instead, you should use Spring's pagination API.
I am new to Hibernate.My senior used 'findAll' method of JpaSpecificationExecutorWithProjection (interface) which is returning result based on a 'LIKE' operator but I required result based on 'AND' operator. Please guide me how I can solve this?.
Below is the part of code which displays it is hitting query based on 'LIKE' operator
where
(
upper(course0_.course_subject) like ?
)
and (
upper(course0_.course_sub_category) like ?
)
and course0_.course_status=?
and (
upper(course0_.course_exam_segment) like ?
)
and (
upper(course0_.course_category) like ?
)
It is using AND operator. The LIKE is for evaluating your individual params.
If you don't like the JPA-methodqueries, you can always write your own in your repository. Below is a quick example incorporating a left join and returning a Page-object. Please take a look here for some basic JPQL
#Query("SELECT p FROM Product p "
+ "LEFT JOIN p.categories category "
+ "WHERE UPPER(p.name) LIKE UPPER(CONCAT('%', COALESCE(:searchRequest, ''), '%')) "
+ "AND UPPER(p.description) LIKE UPPER(CONCAT('%', COALESCE(:description, ''), '%')) "
+ "AND p.price BETWEEN :priceLow AND :priceHigh "
+ "AND p.averageRating >= :averageRating "
+ "AND p.archived = :archived "
+ "AND ((category.name IN :selectedCategories) "
+ "OR (:amountOfSelectedCategories = 0 AND category IN (SELECT c FROM Category c))) "
+ "GROUP BY p "
+ "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"
)
Page<Product> findAllBySearchModel(
Pageable pageable,
#Param("searchRequest") String searchRequest,
#Param("description") String description,
#Param("priceLow") BigDecimal priceLow,
#Param("priceHigh") BigDecimal priceHigh,
#Param("averageRating") double averageRating,
#Param("archived") boolean archived,
#Param("selectedCategories") List<String> selectedCategories,
#Param("amountOfSelectedCategories") int amountOfSelectedCategories
);
I have a query that uses JpaRepository
#Query(
value = "SELECT count(user_name) AS user_count " +
"FROM users " +
"where status = 'B' ",
nativeQuery = true
)
List<Users> usersStatCount();
It gives me an error,
Could not execute query...
The column name user_name was not found in result set
But when I tried the query on pgadmin it is working fine.
And when I tried a simple
#Query(
value = "SELECT * " +
"FROM users " +
"where status = 'B' ",
nativeQuery = true
)
List<Users> usersStatCount();
It is working fine as well.
It's because the query returns a single value, not a row, that has to mapped to entity. Try the following:
#Query(
value = "SELECT count(user_name) " +
"FROM users " +
"where status = 'B' ",
nativeQuery = true
)
Long usersStatCount();
I have the following code which is used to retrieve data from multiple tables (using joins) and then mapping every row into a DTOList but I also need to apply filters based on user preferences: per table1.name or table2.name, table3, etc.
So I just want to know what would be the best way to do it in terms of performance and best practices;
retrieving all rows and then apply the filters with lambdas (easier)
change the query to a dynamic query with Criteria or something else?
Any other solution=?
#Repository
public class ArchiveRepository {
#Autowired
EntityManager em;
String queryStr = "select wsr.id as sampleid, s.id as slideid, tb.name as batchname, k.lot_number as kitlot, " +
" 'STRING' as slidetype, tb.worklist_name as worklist, wsr.final_call as results, " +
" wa.final_pattern_ids as patterns, 'edited/yesno' as edited, wsr.last_modified_by as user, wsr.last_modified_date as time " +
" from slide s " +
" left join table2 tb on s.test_batch_id = tb.id " +
" left join table3 k on tb.kit_lot_id = k.id " +
" left join table4 w on s.id = w.slide_id " +
" left join tabl5 pw on pw.well_id = w.id " +
" left join tabl6 cw on cw.well_id = w.id " +
" left join tabl7 wsr on wsr.patient_well_sample_id = pw.id or wsr.control_sample_id = cw.id " +
" left join (select * from *** (other subselect)) wa on wa.well_sample_id = wsr.**id or wa.well_sample_id = wsr.**id " +
"where tb.state = 'STATENEEDED'";
public ArchiveDataListDTO getArchiveData(){
Query query = em.createNativeQuery(queryStr);
ArchiveDataListDTO archiveDataListDTO = new ArchiveDataListDTO();
List<Object[]> resultL = (List<Object[]>)query.getResultList();
for( Object[] o : resultL){
archiveDataListDTO.addArchiveDataRow(
new ArchiveDataDTO((String)o[0], String.valueOf(o[1]), (String) o[2], (String) o[3], (String) o[4], (String) o[5],
(String) o[6], (String) o[7], (String) o[8], (String) o[9], (String) o[10]));
}
return archiveDataListDTO;
}
}
**
note I struggled some with the code cause I wanted to apply #sqlresultsetmapping to avoid manual results mapping but it just didn´t work, most of the examples out there are when you have an entity in the DB but in this case I retrieve from many tables.**
Thanks so much
2 .- change the query to a dynamic query with Criteria or something else?
I ended up creating the query on the fly; depending on the filters I get from UI i assemble the query with Java and send it to DB, it´s easier since this required many tables...