Is it possible for MyBatis select query to read variable value for Select and Group By commands? If it is possible so how should I put the aggregationKeys variable inside that places? (Look into the code):
#Select({"SELECT #{aggregationKeys}, SUM(value) " +
"FROM usage_counter WHERE " + /*zrobic mape i pociagnac to tak, ze: (#{zmyslona wartosc} IS NULL OR api_consumer) itd*/
"(#{apiConsumerIds} IS NULL OR #{apiConsumerIds} like '%,'||api_consumer||',%' ) AND " +
"(#{serviceIds} IS NULL OR #{serviceIds} like '%,'||service||',%' ) AND " +
"(#{rateplanIds} IS NULL OR #{rateplanIds} like '%,'||rateplan||',%' ) AND " +
"(#{dateFrom} IS NULL OR date >= #{dateFrom} ) AND " +
"(#{dateTo} IS NULL OR date <= #{dateTo} ) AND " +
"(#{statuses} IS NULL OR #{statuses} like '%,'||counter_status||',%' ) " +
"GROUP BY ||#{aggregationKeys}||"})
#Results({
#Result(property = "date", column = "date"),
#Result(property = "apiConsumerId", column = "api_consumer"),
#Result(property = "serviceId", column = "service"),
#Result(property = "value", column = "value")
})
List<AggregatedUsage> getAggregatedUsageCounters(#Param("aggregationKeys") String aggregationKeys, #Param("dateFrom") Date dateFrom, #Param("dateTo") Date dateTo, #Param("apiConsumerIds") String apiConsumerIds, #Param("serviceIds") String serviceIds, #Param("statuses") String statuses);
Edit: Or is it possible to do grouping by in Java streams by two or more values (max 4 in this particular case)?
Second Edit: - ok it is possible but I it makes stream very complicated and I think uneffective.
Related
Having an issue with my simple JPA native query
#Query(value =
"SELECT * FROM transaction " +
"WHERE " +
"( :broker IS NULL OR transaction.broker = :broker ) AND " +
"( :transaction_type IS NULL OR transaction.transaction_type = :transaction_type ) AND " +
"( :asset_id IS NULL OR transaction.asset_id = :asset_id )", nativeQuery = true)
Optional<List<TransactionEntity>> findAllByParams(#Param("broker") Broker broker,
#Param("transaction_type") TransactionType transactionType,
#Param("asset_id") Long assetId);
Broker and TransactionType are enums.
Broker = REVOLUT
TransactionType = TRADE
assetId = 6386
Console is showing this as the query being ran
SELECT * FROM transaction WHERE ( REVOLUT IS NULL OR transaction.broker = REVOLUT ) AND ( TRADE IS NULL OR transaction.transaction_type = TRADE ) AND ( 6386 IS NULL OR transaction.asset_id = 6386 )
Getting this error when running it
[2020-10-30 19:23:42] [42S22][1054] Unknown column 'REVOLUT' in 'where clause'
Don't understand why the named parameters aren't being converted to Strings. Have tried everything I could think of to try force it to a String and nothing has changed it.
my repository:
#Query(value="SELECT t1.foraPonta,t2.ponta,t1.data_medicao From " +
"((SELECT Sum(ativo_c) AS foraPonta, data_medicao FROM my_table WHERE " +
"unidade_id = :unidade_id AND (data_medicao >= :dataInicial AND " +
"data_medicao <= :dataFinal) AND (hora_do_dia >=18 and hora_do_dia <= 20) " +
"GROUP BY data_medicao ORDER BY data_medicao ASC)) AS t1,((SELECT Sum(ativo_c) " +
"as Ponta, data_medicao FROM pc.web_listar_medidas WHERE unidade_id = :unidade_id " +
"AND (data_medicao >= :dataInicial AND data_medicao <= :dataFinal " +
"AND ((hora_do_dia >=0 and hora_do_dia <=17) or (hora_do_dia >=21 and hora_do_dia <=23))) " +
"GROUP BY data_medicao ORDER BY data_medicao ASC)) AS t2 WHERE t2.data_medicao = t1.data_medicao " +
"ORDER BY t2.data_medicao ASC;", nativeQuery=true)
List<Medidas> listarPeriodoForaPonta(#Param("unidade_id") Integer unidade_id,
#Param("dataInicial") Date dataInicial,
#Param("dataFinal") Date dataFinal );
my controller:
#DateTimeFormat(pattern="yyyy/MM/dd")
#GetMapping("/medidas/periodo/{unidade_id}/{dataInicial}/{dataFinal}")
List<Medidas> listaMedidasPeriodo(#PathVariable("unidade_id") Integer unidade_id, #PathVariable("dataInicial") #DateTimeFormat(iso=ISO.DATE) Date dataInicial, #PathVariable("dataFinal") #DateTimeFormat(iso=ISO.DATE) Date dataFinal) {
List<Medidas> medidas = medidasRepositorio.listarMedidasPeriodo(unidade_id, dataInicial, dataFinal);
return medidas;
}
Error message:
org.postgresql.util.PSQLException: The column name id was not found in this ResultSet.
I need to list exactly I wrote in sql query and I do not wanna id column. What I missing?
But from what i can see, you need to make a DTO class with a constructor like
package my.package.dtos;
class MyDTO {
BigDecimal foraPonta;
BigDecimal ponta;
Date data_medicao;
public MyDTO(BigDecimal foraPonta, BigDecimal ponta, Date data_medicao){
this.foraPonta = foraPonta;
this.ponta = ponta;
this.data_medicao = data_medicao;
}
public MyDTO(Double foraPonta, Double ponta, Date data_medicao){
this(new BigDecimal(String.valueOf(foraPonta)), new BigDecimal(String.valueOf(ponta)), data_medicao);
}
}
By the way, i'm just guessing the types of foraPonta, ponta and data_medicao
And your query should look something like
SELECT new my.package.dtos.MyDTO(t1.foraPonta,t2.ponta,t1.data_medicao) From ...
My first step would be to double check that the Medidas class has the properties corresponding to the column names, and all properties marked as mandatory in Medidas are in the set of the returned columns:
foraPonta
ponta
data_medicao
i have a named query where I want to fetch all records where year and month of a parameter match the database entry:
#NamedQuery(
name = entries.queryX,
query = "SELECT DISTINCT t from entries t " +
"where MONTH(t.myMonth) = :month " +
"and YEAR(t.myMonth) = :year "
)
The value "myMonth" in table entries is a YearMonth:
#Column(name = "MY_MONTH", precision = 7)
private YearMonth myMonth;
I set the query parameters as follows:
query.setParameter("month", date.get(Calendar.MONTH) + 1);
query.setParameter("year", date.get(Calendar.YEAR));
However, this approach does not work... Is there any other way to implement what I want to search for?
I am trying to execute a Native Query from a Spring Boot application, but i am getting this error " org.postgresql.util.PSQLException: ERROR: operator does not exist: integer = bytea "
Here are the codes i have written to implement this
#SqlResultSetMapping(
name = "StudentAssessmentValue",
classes = #ConstructorResult(
targetClass = StudentAssessmentDTO.class,
columns = {
#ColumnResult(name = "subject_title", type = String.class),
#ColumnResult(name = "assessment", type = String.class),
}
)
)
#NamedNativeQuery(
name = "getStudentSubjectsAssessment",
query = "SELECT\n" +
" subject.subject_title,\n" +
" j as assessment\n" +
"FROM assessment s\n" +
"JOIN LATERAL jsonb_array_elements(s.assessment) j(elem) ON (j.elem->>'student_id') = :student_id\n" +
"JOIN subject ON subject.id = s.subject_id\n" +
"WHERE s.subject_id IN (:subjects)\n" +
"AND s.academy_year_id = :academy_year_id\n" +
"AND s.term_id = :term_id\n" +
"AND s.section_id = :section_id"
,
resultSetMapping = "StudentAssessmentValue"
)
This is the code in my Respository
#Query(nativeQuery = true, name = "getStudentSubjectsAssessment")
List<StudentAssessmentDTO> getStudentAssessments2(
#Param("student_id") String student_id,
#Param("academy_year_id") Integer academy_year_id,
#Param("section_id") Integer section_id,
#Param("term_id") Integer term_id,
#Param("subjects") Integer[] subjects
);
And i have this in my controller
#GetMapping("/{student_id}/{academy_year_id}/{section_id}/
term_id}")
public List<StudentAssessmentDTO> getStudentAssessment2(
#PathVariable("student_id") String student_id,
#PathVariable("academy_year_id") Integer academy_year_id,
#PathVariable("section_id") Integer section_id,
#PathVariable("term_id") Integer term_id,
#RequestParam(value = "subjects") Integer[] subjects
){
return assessmentService.getStudentAssessments2(student_id, academy_year_id, section_id, term_id, subjects);
}
I have also notice if i remove this part from the query
WHERE s.subject_id IN (:subjects) or say i hard code the subjects value like so s.subject_id IN (2,3,4) the code runs successfully. But if the value is coming from the request i then get the error. Here is how the request looks like
localhost:8080/assessment/f3df0bc2-7b4c-49b9-86c9-6e6b01628623/3/4/1?subjects=2,3,4
I recently had a similar problem to yours, while also working with a native JPA query on Postgres. Here is what worked for me:
// sqlString contains your native query
Query query = entityManager.createNativeQuery(sqlString, StudentAssessmentDTO.class);
query.setParameter("subjects", subjects);
query.setParameter("academy_year_id", new TypedParameterValue(IntegerType.INSTANCE, academy_year_id));
query.setParameter("term_id", new TypedParameterValue(IntegerType.INSTANCE, term_id));
query.setParameter("section_id", new TypedParameterValue(IntegerType.INSTANCE, section_id));
List< StudentAssessmentDTO > = query.getResultList();
The error you are seeing can be explained by the Postgres JDBC driver's inability to correctly pass needed type information to the database. For instance, the following error:
ERROR: operator does not exist: integer = bytea
would occur because the driver is passing the parameter to Postgres as a byte array, but the target column is integer type. By using the above type "hints," we can force the driver to pass the correct type information.
This might not be the best solution to this, but it is working for me, i will be glad if anyone can still provide a better solution.
Here is what i did:
I wrote a method that will take the array gotten from the request and generate a string of this nature "(a,b,c)" and then added this string to my query string and it work
CODE
This is the method that build the string
NOTE: I can afford to use this function because i know for sure them element of this array does not grow rapidly, max for my case will be 15
public String generateInSearchParameter(Integer[] inputArr){
StringBuilder search = new StringBuilder("(");
IntStream.range(0, inputArr.length).forEach(i -> {
if (i != inputArr.length - 1) {
search.append(inputArr[i]).append(',');
} else {
search.append(inputArr[i]);
}
});
search.append(")");
return search.toString();
}
Here is the controller code
#GetMapping("/{student_id}/{academy_year_id}/{section_id}/{term_id}")
public List<StudentAssessmentDTO> getStudentAssessment2(
#PathVariable("student_id") String student_id,
#PathVariable("academy_year_id") Integer academy_year_id,
#PathVariable("section_id") Integer section_id,
#PathVariable("term_id") Integer term_id,
#RequestParam(value = "subjects") Integer[] subjects
){
return assessmentService.getStudentAssessments2(student_id, academy_year_id, section_id, term_id,generateInSearchParameter(subjects));
}
Here is the code in my Service
public List<StudentAssessmentDTO> getStudentAssessments2(
String student_id, Integer academy_year_id,
Integer section_id, Integer term_id, String subjects
){
String sqlString = "SELECT" +
" subject.subject_title," +
" j.*" +
" FROM assessment s" +
" JOIN LATERAL jsonb_array_elements(s.assessment) j(elem) ON (j.elem->>'student_id') = :student_id" +
" JOIN subject ON subject.id = s.subject_id" +
" WHERE s.academy_year_id = :academy_year_id" +
" AND s.section_id = :section_id" +
" AND s.subject_id IN " + subjects +
" AND s.term_id = :term_id";
Query query = entityManager.createNativeQuery(sqlString, "StudentAssessmentValue");
query.setParameter("academy_year_id", new TypedParameterValue(IntegerType.INSTANCE, academy_year_id));
query.setParameter("term_id", new TypedParameterValue(IntegerType.INSTANCE, term_id));
query.setParameter("section_id", new TypedParameterValue(IntegerType.INSTANCE, section_id));
query.setParameter("student_id", new TypedParameterValue(StringType.INSTANCE, student_id));
return query.getResultList();
}
I will be guard to welcome a better solution if provided
First of all, I have a working query for MERGE INTO if I directly run it on database. I want to SET NULL to some columns with MERGE INTO WHEN MATCHED THEN part. It simply doesn't work when I use it with Hibernate.
This is how my method looks like :
#Modifying
#Transactional
#Query(nativeQuery = true,
value = "MERGE INTO APP_TOKEN t " +
"USING DUAL " +
"ON ( t.TYPE = :appTokenType " +
" AND t.TOKEN = :token " +
" AND t.IS_DELETE = 0 " +
") " +
"WHEN MATCHED THEN " +
" UPDATE SET " +
" t.APP_USER_ID = :appUserId, " +
" t.APP_DEVICE_ID = :appDeviceId, " +
" t.EXPIRY_DATE = :expiryDate, " +
" t.UPDATED_DT = :updatedDt, " +
" t.UPDATED_BY = :updatedBy " +
"WHEN NOT MATCHED THEN " +
" INSERT (APP_USER_ID, APP_DEVICE_ID, TYPE, TOKEN, EXPIRY_DATE, IS_DELETE, STATUS, CREATED_BY, CREATED_DT, UPDATED_BY, UPDATED_DT) " +
" VALUES (:appUserId, :appDeviceId, :appTokenType, :token, :expiryDate, :isDelete, :status, :createdBy, :createdDt, :updatedBy, :updatedDt) ")
int upsert(#Param(value = "appUserId") Long appUserId,
#Param(value = "appDeviceId") Long appDeviceId,
#Param(value = "appTokenType") String appTokenType,
#Param(value = "token") String token,
#Param(value = "expiryDate") Date expiryDate,
#Param(value = "isDelete") Boolean isDelete,
#Param(value = "status") String status,
#Param(value = "createdBy") Long createdBy,
#Param(value = "createdDt") Date createdDt,
#Param(value = "updatedBy") Long updatedBy,
#Param(value = "updatedDt") Date updatedDt);
The appUserId (first parameter) of the method may be NULL, and I want to update this column to NULL (in database) if the parameter is NULL (in Java).
The following exception is thrown when the appUserId is NULL :
java.sql.sqlsyntaxerrorexception ora-00932 inconsistent datatypes expected number got binary
Framework/ Library I used :
Spring MVC 5.0.4.RELEASE
Spring Data JPA 2.0.0.RELEASE
Hibernate 5.2.16.Final
Database : Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production
Is Hibernate able to handle setting NULL with UPDATE ?
EDIT :
I have tried with simple UPDATE ... SET ... statement to set some column to NULL, but still not successful