How to CAST twice an element in a row JPA - java

I've done a query with PostgreSQL that retrieves certain data as I expected: (It works)
SELECT distinct d.data
FROM myScheme.myTable d, myScheme.mySecondTable g, json_array_elements(d.data->>'categorys') e
where d.data->>'categorys' is not null
AND e::text::int in (g.id_product_category_magento)
AND e::text::int IN (21718, 17);
The problem is when I try to do the same query with Java using JPA. This is not worked script:
#Query(
nativeQuery = true,
value = "SELECT DISTINC d.data " +
"FROM myScheme.myTable d, myScheme.mySecondTable g, " +
"json_array_elements(d.data->>'categorys') e " +
"where d.id = :id AND d.data->>'categorys' is not null " +
"AND CAST(CAST(e as text) as Integer) in (g.id_product_category_magento) " +
"AND CAST(CAST(e as text) as Integer) IN (:categories)"
)
List<ServiceDefinition> yest(Set<Long> categories, #Param("id") Long id);
The stack trace throws the following error message:
No dialect for Mapping JDBC 1111
Things to keep in mind:
b.data ->> 'categorys' is an array of Strings that contains string values such as: ['123', '456', '789'] and should return each one of this values.
Pd: I'm not sure if this is the right way to cast a value twice: AND CAST(CAST(e as text) as Integer).

I found the solution to this:
I saved from casting each element twice by using json_array_elements_text instead of json_array_elements, the first one returns the values already as Strings. The second one was producing this error message: No dialect for mapping 1111 due to a bad cast syntax made by me. This thanks to the wonderful suggestion from #AdrianKlaver
Doing select d.data seemed not to work, because it was returning an unknown data type for Hibernate, instead I returned d.idbecause I was really expecting each categoryId as Long type.
Used this CAST(e as int4) instead of this as Integer
Removed an extra #Param (id) of my yest() method
The final query is as shown below:
#Query(
nativeQuery = true,
value = "SELECT distinct d.id FROM myScheme.myTable d, myScheme.mySecondTable g " +
",json_array_elements_text(d.data->>'categorys') e " +
"where d.data->>'categorys' is not null " +
"AND CAST(e as int4) in (g.id_product_category_magento) " +
"AND CAST(e as int4) in (:categories)"
)
List<Long> yest(List<Long> categories);
Hope this helps someone in the future. :)

Related

How to compare LocalDateTime values in JPQL query?

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

No Value specified for parameter 2

I am getting this error when trying to run my Spring boot.
java.sql.SQLException: No value specified for parameter 2
My code is this:
public UserTemp findHistoryByID(Integer Patient_Number) {
String sql = "select Col1\n" +
"from (\n" +
" select Past_Diagnoses_1 as Col1\n" +
" from patienthistory\n" +
" where Patient_Number = ?\n" +
" union\n" +
" select Past_Diagnoses_2 as Col1\n" +
" from patienthistory" +
" where Patient_Number = ?" +
" ) as T;";
return jdbcTemplate.queryForObject(sql, new Object[]{Patient_Number}, (rs, rowNum) ->
new UserTemp(
rs.getString("Col1")
));
}
As in the comments, you are having 2 placeholders in the SQL query. So you have to pass patient_number 2 times.
Coming to your second question, it depends on your requirement.
If you need a single result, you need to fix it on the DB side as it's a data issue or the query used is not proper.
If more than one result is allowed, you can use jdbcTemplate.queryForList() instead of jdbcTemplate.queryForObject(). And change the return type of findHistoryByID() to List<Map<String,Object>> and all callers of this function.
Note: Here key for each Map in List is column names returned from DB.
More information on jdbcTemplate.queryForList() is in official documentation

using in clause inside jpa query gives Operand should contain 1 column(s) error

i'm trying to use in clause inside a jpa query but it gives Operand should contain 1 column(s) error.
Here is my query:
#Query(value = "select e from Table e where " +
"((:plantId is null and :unitId is null and :functionalLocationId is null) or" +
" (:functionalLocationId is not null and e.functionalLocation.id in (select f.id from FunctionalLocation f where f.id = :functionalLocationId)) or" +
" (:unitId is not null and :functionalLocationId is null and e.functionalLocation.unit.id in (select u.id from Unit u where u.id = :unitId)) or" +
" (:plantId is not null and :unitId is null and :functionalLocationId is null and e.functionalLocation.unit.plant.id in (select p.id from Plant p where p.id = :plantId))) and" +
"((:equipmentTagNumbers) is null or e.tagNo in (:equipmentTagNumbers)) and" +
"(:startDate is null or e.lastUpdateDate >= :startDate) and" +
"(:endDate is null or e.lastUpdateDate <= :endDate)" +
"order by e.id desc")
:equipmentTagNumbers property is a Lis<String> and if i send null for it query works as i expected but when i send actual data it gives the error.
any suggestions?
As far as i understood there is no isEmpty or length in jpa queries if your parameter is an array like in this case. #SOlsson was right (1,2,4 is null or... is not valid Sql so i decided to add an extra parameter to my query in order to check if its null or not so my last query like:
...
"((:hasEquipmentNumbers) is null or e.tagNo in (:equipmentTagNumbers)) and"
...
:hasEquipmentNumbers is a Boolean which i can assign null so if its null then nobody hurts and if its not i can run my IN clause with no trouble.
PS:I marked his answer cuz, it seemingly like an answer. But i implemented like i explain.
((:equipmentTagNumbers) is null or...
becomes
(1,2,4 is null or...
which is not proper SQL.
Instead, go like this:
#Query(value = "select e from Table e where " +
"..." +
(equipmentTagNumbers == null ? "" : "e.tagNo in (:equipmentTagNumbers)) and ") +
"..." +
"order by e.id desc")
That way equipmentTagNumbers does not affect the query when it is null.

Spring data jpa, Native Query, returned wrong field types

I have following native query method in my repository:
#Query(value="SELECT appSub.ApplicationFormId as appFormId, appSub.profileId as profileId, "
+ "p.CASId as profileCASId, ps.programId as programId FROM [unicas_config].[dbo].ApplicationFormEarlyDecisionConfig appFormED "
+ "INNER JOIN [unicas_ux].[dbo].ApplicationSubmission appSub ON appFormED.ApplicationFormId = appSub.applicationFormId "
+ "INNER JOIN [unicas_ux].[dbo].Profile p ON appSub.profileId = p.id "
+ "INNER JOIN [unicas_ux].[dbo].ProgramSelected ps ON p.id=ps.ProfileId AND appSub.applicationFormId = ps.instanceId "
+ "WHERE appFormED.EarlyDecisionVerdictDate >=:fromDate AND appFormED.EarlyDecisionVerdictDate <:toDate "
+ "AND appSub.EarlyDecisionStatus='Applied Early Decision' "
+ "AND appSub.ApplicationStatus='Received' "
+ "AND ps.IsPaid =1 "
+ "ORDER BY appSub.ApplicationFormId",nativeQuery = true)
List<Object[]> getAllEarlyDecisionApplicantsWithPaidProgramsOnVerdictDate(#Param("fromDate") Date fromDate, #Param("toDate") Date toDate);
Now, I want to map the returned result:
long appFormId = (Long)obj[0]
long profileId = (Long)obj[1]
long programId = (Long)obj[3]
When I am doing that, I am getting java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long as Hibernate consider these ids of Integer type instead of Long.
Please, tell me how could I programatically tell Hibernate to return proper type.
To be on the safe side, I always cast numeric types to Number and then get the value of desired type from it, as JDBC driver can return Integer, Long, BigDecimal, etc. depending on the type of the database column:
((Number) obj[0]).longValue()
Of course, don't forget to check for null if column is nullable.

Number of characters in sql query result

I am using Spring 3.1.1 with Hibernate 4 and a MSSQL database. Finally, I have been able to query my database with joins in my table that returns the correct answers. Although, it seems that it does not return the entire strings of my messages, but cuts at 29/30 digits. Here is my query:
SQLQuery sql = this.getCurrentSession().createSQLQuery(
"SELECT event.id as eventid, CAST(event_type.type_name AS varchar) as eventtype, event.check_date, event.event_date, event.status, CAST(event_message.message AS varchar) as eventmessage " +
"FROM event_log event " +
"LEFT JOIN event_type " +
"ON (event.event_type_id = event_type.id) " +
"LEFT JOIN event_message " +
"ON (event.event_message_id = event_message.id) " +
"WHERE event.event_type_id = " + jobId +
"ORDER BY eventid");
The result can be:
4506 Database 2014-01-15 14:14:15.02 2014-01-15 14:14:15.02 false Database-connection cannot be
Where the columns are id, task_name, check_date, event_date, status and the message-string at the end. .
The result goes to a ArrayList<Object[]> where I read row[0] etc. to get the entities in the row. The string message gets cut after 29 digits, which is disturbing. Why does it cut the string and how can I fix this? In my database the string exists in it's full and is entitled 400 characters max.
I know this is probably not the best way to query my database, but it will do for my application since it works.
You are using varchar without a length. Never do this!
Replace:
CAST(event_type.type_name AS varchar)
With something like:
CAST(event_type.type_name AS varchar(255))
In some contexts, the default length is 32. In some it is 1. In general, though, always specify the length.
EDIT:
Actually, you probably don't even need the cast. Why not just have event_type.type_name in the select list?

Categories

Resources