MySQL SELECT WHERE... AND (based on parameter value) - java

#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.

Related

Java convert Postgres query into JPA Criteria builder

I have this sql query which I am using native sql to process currently and I need to transform it to use the JPA criteria builder so I can dynamically build up the where conditions. I am currently semi building the conditions dynamically in a janky way in sql (AND (case when 0 in :#{#filter.modelIds} then true else model_id in :#{#filter.modelIds} end)
Also, Im not sure what the best practices are and if I should just leave the code I currently have or move it over to Criteria builder. A lot of articles I read have said not to use criteria builder for advance quires. For me everything works but some people expressed concerns over the maintainability of the code. To me I like looking at sql versus the criteria builder just confuses me :)
Another blocker for me is I'm using the Postgres function generate_series to create all the dates in a date range so that way I can have empty values for dates with no data. I was not sure how to translate this over to the criteria builder I figured out how to use the date trunc function Expression<Date> view_date = builder.function("date_trunc", Date.class, builder.literal("day"), root.get("acquisitionDate")); The only other thought I had was to just execute the sub query and the use java to build up the date array and map my results to it
SQL:
select date, COALESCE(views, 0) as count, model_id
from generate_series(date '2020-05-9',date '2020-05-18',interval '1 day')as t(date)
left join (
select date_trunc('day',acquisition_date) as view_date, count(acquisition_date) as views, model_id
from view
where acquisition_date between '2020-05-9' and '2020-06-19'
group by model_id, view_date
order by view_date asc
) as v on v.view_date = date
order by date asc;
Repository:
#Query(
value = "select date, COALESCE(views, 0) as count, d.model_id as itemId " +
"from generate_series(date (:#{#filter.startDate}),date (:#{#filter.endDate}), CAST('1'||' '||:#{#filter.getInterval()} AS Interval))as t(date)" +
"left join (" +
"select date_trunc((:#{#filter.getInterval()}),acquisition_date) as view_date, count(acquisition_date) as views, model_id " +
"from view " +
"WHERE acquisition_date between (:#{#filter.startDate}) and (:#{#filter.endDate})" +
"AND (case when 0 in :#{#filter.modelIds} then true else model_id in :#{#filter.modelIds} end)" +
"AND (case when '0' in :#{#filter.imageIds} then true else image_id in :#{#filter.imageIds} end) " +
"AND (case when 0 in :#{#filter.objectIds} then true else object_type_id && array[(:#{#filter.getObjectArray()})] end)" +
"group by model_id, view_date " +
"order by view_date asc" +
") as v on v.view_date = date_trunc((:#{#filter.getInterval()}), date) " +
"order by date asc",
nativeQuery = true
)
List<ItemDateCountProjection> getModelViewsByDate(#Param("filter") ViewFilter filter);
Projection
public interface ItemDateCountProjection {
String getItemId();
Integer getCount();
Date getDate();
}

Bind #param in a Jpa repository native query inside single quotations

I am looking for a way to bind a given param in a native query where the value has to be inside single quotations, like so:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - interval ':timeThreshold' HOUR " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);
However, when I try to run this, it results in hibernate not being able to bind the timeThreshold value as it is provided inside the single quotations ''.
Does anyone know how this can be resolved?
The problem you are having with your native Oracle query has to do with trying to bind a value to an interval literal. You can't do that. Instead, use the NUMTODSINTERVAL() function:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - numtodsinterval(:timeThreshold, 'hour') " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);

column not found in result set

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();

Implement JPA Projection with count

I want to implement JPA Projection with count. I tried this:
#Query(value = "SELECT new org.service.PaymentTransactionsDeclineReasonsDTO( id, count(id) as count, status, error_class, error_message) " +
" FROM payment_transactions " +
" WHERE terminal_id = :id AND (created_at > :created_at) " +
" AND (status != 'approved') " +
" GROUP BY error_message " +
" ORDER BY count DESC", nativeQuery = true)
List<PaymentTransactionsDeclineReasonsDTO> transaction_decline_reasons(#Param("id") Integer transaction_unique_id, #Param("created_at") LocalDateTime created_at);
But I get error: Caused by: java.sql.SQLException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.plugin.service.PaymentTransactionsDeclineReasonsDTO( id, count(id) as c' at line 1
How I can implement proper count when I have class based Projection?
Try Interface-based Projection instead of DTO:
public interface TransactionDeclineReason {
Integer getId();
Long getCount();
Status getStatus();
ErrorClass getErrorClass(); // I suppose it's enum...
String getErrorMessage();
}
#Query(value = "select " +
"id as id, " +
"count(id) as count, " +
"status as status, " +
"error_class as errorClass, " +
"error_message as errorMessage " +
"from " +
"payment_transactions " +
"where " +
"terminal_id = ?1 " +
"and created_at > ?2 " +
"and status != 'approved' " +
"group " +
"by error_message " +
"order by " +
"2 desc", nativeQuery = true)
List<TransactionDeclineReason> getTransactionDeclineReasons(Integer transactionId, LocalDateTime createdAt);
Pay attention on aliases (i.e. id as id) - they are mandatory.
You are mixing JPQL and SQL syntax.
The constructor expression (new ...) is JPQL, but in the annotation you mark it as a nativeQuery i.e. as SQL so you have to make up your mind.
If it is to be SQL I don't think you can use aliases in the ORDER BY clause, so you might have to either repeat the expression or wrap it in a subselect as described here: Using an Alias in a WHERE clause.
If it is to be JPQL it doesn't support aliases in a constructor expression, so I guess you have to repeat the expression in the order by clause.

LIKE COALESCE in Spring JPA does not work

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.

Categories

Resources