Ok, I'm rather new to Spring Boot and I'm currently facing a problem with attempting to successfully run the following Query towards my MySQL-Database in Postman without receiving a list of null-values:
#Query("SELECT user.id, user.email FROM ProjectUser user WHERE user.lastLogin IS NOT NULL AND user.userType = 'Test'")
List<ProjectUser> test1();
User.id and user.email is of type bigint(20) and VARCHAR(255) in the database, and I suspect that it might be related to them not being declared as NVARCHAR, but I have not tried modifying this as I'm scared it will corrupt the database :P. However, I see that the conditioning works as the number of objects returned is correct, so I'm suspecting that the issue is mainly related to representing the values.
In comparison, the following NativeQuery works and returns non-null values in Postman:
#Query(value = "SELECT id, email FROM user WHERE last_login IS NOT NULL AND user_type = 'Test'", nativeQuery = true)
List<ProjectUser> test1();
I was just wondering if anyone here might have an idea to how to fix this problem? I don't necessarily see why I should not go with the NativeQuery-solution when it works, but it is more of curiosity and understanding the problem.
You should strictly distinguish hql/jpql query and native sql query.
When you use explicit list of columns in jpql select clause that means you should expect result as List<Object[]>.
So, for your case, you should correct the query in the following way:
#Query("SELECT user FROM ProjectUser user WHERE user.lastLogin IS NOT NULL AND user.userType = 'Test'")
List<ProjectUser> test1();
For more detailed explanation about values you can use in SELECT clause see the documentation.
Related
I am trying to use Spring Data Pageable with JPA Query (Not native) which cases the following exception:
Caused by: java.sql.SQLSyntaxErrorException: Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'alerting.alerthisto0_.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Here is my query:
#Query(value =
"SELECT history.alertId AS alertId, history.userId AS userId, alert.organization.id AS organizationId,"
+ " alert.status AS status, alert.createdAt AS createdAt, COUNT(history.alertId) AS alertsCount"
+ " FROM AlertHistory AS history LEFT JOIN Alert AS alert ON history.alertId=alert.id"
+ " GROUP BY history.alertId, history.userId")
Page<AlertAggregationDetails> groupByAlertIdAndUserId(Pageable pageable);
Apparently, because I am using Pageable history.id is injected which is unnecessary and causing syntax issue. If I add history.id to the group by section the syntax will be correct but obviously, the result is far from what I'd like to have. I was wondering if there is a way to fix the syntax issue and continue using Pageable.
Also, if I remove Pageable this query works and there is no issue.
EDIT:
After I debug the query I noticed that Spring JPA added ORDER BY history.id to my query automatically when I use Pageable. As a workaround, I can replace sql_mode, but I don't understand why I cannot overwrite ORDER BY with Pageable.
AFAIK Spring Data by default adds the entity id as order by expression if you don't add any sorts which might be what you see. It makes sense, because you want a consistent ordering, otherwise pagination wouldn't work. You will have to add the sorts alertId and userId for MySQL to be happy and also get consistent results.
After switching from MySQL to PostgreSQL I found out that my SQL query (#Query in spring data repository interface) does not work anymore. The issue is caused by null value being sent as bytea and I'm getting following exception:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: bigint = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Repository with #Query:
public interface WineRepository extends PagingAndSortingRepository<Wine, Long> {
#Query(value = "SELECT * FROM WINE w WHERE (?1 IS NULL OR w.id = ?1)", nativeQuery = true)
Wine simpleTest(Long id);
}
Simple test:
LOGGER.warn("test1: {}", wineRepository.simpleTest(1L)); //ok
LOGGER.warn("test2: {}", wineRepository.simpleTest(null)); //PSQLException
In the real case I have multiple parameters which can be null and I would prefer not checking them in java code but sending them to sql query. I have checked questions here on stackoverflow but found none with a good answer especially for spring data repository #query annotation.
What is a correct way of handling null values with PostgreSQL? Or do you have any hints how to fix my approach? Thanks!
Update:
Issue seems to be related to nativeQuery = true, when value is false, null values work as expected. So the question is whether it is possible to make it function even with nativeQuery enabled.
Try this.
SELECT *
FROM WINE w
WHERE ?1 IS NULL OR w.id = CAST(CAST(?1 AS TEXT) AS BIGINT)
It satisfies the type checker and should have the same properties as the original query. CAST is not a big performance hit if it happens on a constant value rather than a value from a database row.
You are trying to check whether a Java null is equal to Postgres NULL which I think is not necessary. You can rewrite as following and avoid sending null to the simpleTest function at all.
#Query(value = "SELECT * FROM WINE w WHERE (w.id IS NULL OR w.id = ?1)", nativeQuery = true)
Wine simpleTest(Long id);
I had a similar issue in an #Query where a Long was being interpreted by Postgres as a bytea. The solution for me was to unbox the #Param...by passing a long value, Postgres correctly interpreted the value as a bigint
I know it is an old issue, but you should be able to fix that bay casting the java value. Something like:
public interface WineRepository extends PagingAndSortingRepository<Wine, Long> {
#Query(value = "SELECT * FROM WINE w WHERE (?1\\:\\:bigint IS NULL OR w.id = ?1\\:\\:bigint)", nativeQuery = true)
Wine simpleTest(Long id);
I am using jpa native query , but its not returning values from salias it returns values from S
Query query = em.createNativeQuery("Select S.\"MESSAGE\",S.\"DESTINATION\",S.\"SENT_DATE\",S.\"CLIENT_TRACKING_ID\",S.\"MESSAGE_COST\",S.\"sTId\",salias.\"STATUS\",salias.timeDate from \"sent_sms_view\" S left join ( Select Distinct on (\"SMS_ID\") R.\"SMS_ID\",R.\"STATUS\",R.timeDate from \"sms_receipt_view\" R Order By R.\"SMS_ID\",R.timeDate Desc)As salias on S.\"SYSTEM_TRACKING_ID\"=salias.\"SMS_ID\" where S.Id_systemUser=:systemUser and S.\"CLIENT_TRACKING_ID\"=:cTId");
query.setParameter("cTId", cTId);
query.setParameter("systemUser", systemUser);
if (query.getResultList().size() > 0){
List<Object> resultat = query.getResultList();
This is the Postgres query and it works fine
Select S."MESSAGE",S."DESTINATION",S."SENT_DATE",S."CLIENT_TRACKING_ID",S."MESSAGE_COST",S."sTId" ,salias."STATUS",salias.timeDate
from "sent_sms_view" S
left join ( Select Distinct on ("SMS_ID") R."SMS_ID",R."STATUS",R.timeDate from "sms_receipt_view" R Order By R."SMS_ID",R.timeDate Desc)As salias
on S."SYSTEM_TRACKING_ID"=salias."SMS_ID"
where S.Id_systemUser='101' and S."CLIENT_TRACKING_ID" ='abda';
Can anyone tell me what i am doing wrong.
I'm only guessing what you might be trying to do, since you haven't told us, but here's how I'm guessing it should probably look like:
SELECT S."MESSAGE", S."DESTINATION", S."SENT_DATE", S."CLIENT_TRACKING_ID", S."MESSAGE_COST", S."sTId", salias."STATUS", salias.timeDate
FROM "sent_sms_view" S
INNER JOIN "sms_receipt_view" AS salias on (S."SYSTEM_TRACKING_ID" = salias."SMS_ID")
WHERE S.Id_systemUser=:systemUser AND S."CLIENT_TRACKING_ID"=:cTId
However I don't see why you would have numerical IDs, such as Id_systemUser stored as strings. In fact that variable name indicates horrible database design. CamelCasing combined with underscores is something you must categorically avoid.
And you must never call query.getResultList() twice if you're looking for the same results. Simply store the List to a local variable and then use it.
While running the below query to get the latest message with the latest data using the createdOn column
i get the below error
select count(m) from MessageWorkFlowStatus mwfs1 where mwfs1.createdOn =(select max(createdOn) from MessageWorkFlowStatus mwfs2 where mwfs1.status= 'NEW' or mwfs1.status='IN PROGRESS')
The encapsulated expression is not a valid expression
Please let me know if i can run Query this way
First of all, count(m) is not correct. It should either be count(*) or count(mwfs1). Secondly, in your inner query, you are using status column from the outer query table (mswfs1) which is logically wrong. It should instead be mwfs2.status = 'NEW' or mwfs2.status = 'IN PROGRESS'.
I think your query should be:
select count(mwfs1)
from MessageWorkFlowStatus mwfs1
where mwfs1.createdOn = (
select max(createdOn)
from MessageWorkFlowStatus mwfs2
where mwfs2.status= 'NEW' or mwfs2.status='IN PROGRESS')
I need to use the LIKE operator into an JPA query. I need to use it for types other then String but the JPA criteria API allows me to add only String parameters. I tried using the .as(String.class) but something fails and also tried calling the CAST function from the underlying Oracle that again fails for unknown reasons to me.
I tried writing the query also in JPQL and it works as expected. This is the query:
SELECT p from CustomerOrder p where p.id like '%62%'
UPDATE:
The query must be built in a generic fashion as it is for filtering, so it needs to be created at runtime. On the query that is already created I tried to add the LIKE clause like this:
query.where(builder.like(selectAttributePath.as(String.class), "%"+filterValue.toString().toLowerCase()+"%"));
But this crashes with this exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found '(' near line 1, column 156 [select distinct generatedAlias0.id from de.brueckner.mms.proddetailschedact.data.CustomerOrder as generatedAlias0 where cast(generatedAlias0.id as varchar2(255 char)) like :param0]
I executed the same query directly to Oracle using SQLDeveloper, so it should be sound from this point of view. So the problem is the Hibernate is the issue. Any suggestions on how to fix it?
How can I write this query using JPA Criteria?
I fixed the problem by invoking the 'TO_CHAR' function from the underlying Oracle DB and using the LIKE operator like for normal String's.
query.where(builder.like(selectAttributePath.as(String.class), "%" +filterValue.toString().toLowerCase() + "%")
You can try the below code, it might require modifications.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CustomerOrder> cq = cb.createQuery(CustomerOrder.class);
Root<CustomerOrder> order = cq.from(CustomerOrder.class);
cq.where(cb.like(Long.valueOf(order.get(CustomerOrder_.id)).toString(), "%62%"));
TypedQuery<CustomerOrder> q = em.createQuery(cq);
List<CustomerOrder> results = q.getResultList();