I'm new to JPA and have the below JPA query:
String qry = " SELECT e from Event e"
+ " WHERE e.meeting.meetingDate= :pdate"
+ " AND e.meeting.feedId IN (1,2)"
+ " AND e.status <> 'W'"
+ " AND e.meeting.status ='A'"
+ " AND e.settleStatus is NULL"
+ " AND e.offTime is NULL"
+ " AND e.eventCode >'07:45:00'"
+ " group by e.id";
And I need to add the ORDER BY clause dynamically. I use MySQL and please anybody tell me how to add below condition to my query using JPA.
part to add:
ORDER BY
CASE WHEN m.country_code ='AU' THEN e.timestamp_updated
WHEN m.country_code <> 'AU' THEN e.event_code
END DESC
how to add this query segment in to my JPA query?
Since JPA 2.0 you can use CASE WHEN in JPQL.
So you just have to do something like that:
ORDER BY
CASE
WHEN (e.property = ?) THEN 1
WHEN (e.property = ?) THEN 2
ELSE 3
END DESC
You can also use Criteria API
Criteria criteria = session.createCriteria(YourEntity.class);
if(clause){
criteria.addOrder( Order.asc("property_desired_1") );
}else{
criteria.addOrder( Order.asc("property_desired_2") );
}
criteria.list();
You can se more about criteria here, about JPQL CASE WHEN here and about Order here
This works protty god for me
My NATIVE Sql query
SELECT
another_column1, another_column2
CASE
WHEN property_column = 'AU' then value_column ELSE 0
END AS LEARN,
CASE
WHEN property_column = 'EU' then value_column ELSE 0
END AS Contribute
FROM testing.mytablename;
JpaRepository / JPQL Query: returning a List < tuple >
public interface MyTableRepository extends JpaRepository<MyTable, UUID> {
//c.columnNames are properties of MyTable class
// take care of spaces and , caracters
#Query("SELECT c.anotherColumn1, c.anotherColumn2, " +
" CASE c.propertyColumn WHEN 'AU' then c.valueColumn ELSE 0 END as learn," +
" CASE c.propertyColumn WHEN 'EU' then c.valueColumn ELSE 0 END as transfer "
"FROM MyTable AS c ")
List<Tuple> selectByPropertyCase();
}
FINALLY, if you want to MAP your query in a DTO Class
public interface MyTableRepository extends JpaRepository<MyTable, UUID> {
//make sure to create the constructor for the dto classs
#Query("SELECT SELECT new com.myprojectpath.model.MyTableClassDTO(c.anotherColumn1, c.anotherColumn2, " +
" CASE c.propertyColumn WHEN 'AU' then c.valueColumn ELSE 0 END as learn," +
" CASE c.propertyColumn WHEN 'EU' then c.valueColumn ELSE 0 END as transfer) "
"FROM MyTable AS c ")
List<MyTableClassDTO> selectByPropertyCase();
}
Related
I am using hibernate for this select:
NativeQuery sqlQuery = session.createSQLQuery("select :id, min(a.time) " +
"from table1 a, (" +
" select parentid" +
" from (" +
" select LEVEL, parentid" +
" from table2 " +
" START WITH id = :id" +
" CONNECT BY NOCYCLE PRIOR parentid = id" +
" order by level desc)" +
" where rownum = 1" +
" ) b " +
"where a.id = b.parentid");
sqlQuery.setParameter("id", id);
List<Object[]> list = sqlQuery.list();
I need to use this for a lot of ids. Ideally I would pass a list of ids, run that in oracle and return the result. I cannot do that because of the START WITH clause.
This way I send a query to database for each id, which is really slow.
Is there any way to put a list of ids to the query, do this in loop and return back to the application with a list of results?
NativeQuery sqlQuery = session.createSQLQuery("...?...");
sqlQuery.setListParameter("ids", ids);
List<Object[]> list = sqlQuery.list();
Edit: I cannot use recursive with, because we use Oracle 10.
I don't know about the Oracle specific syntax, but with the SQL standard WITH RECURSIVE syntax, you can of course list multiple parameters. Just use the IN predicate e.g. for batches of 5 id IN (:id1, :id2, :id3, :id4, :id5) and then bind the values with setParameter("id1", ...). If you are interested, you can also formulate this with Blaze-Persistence on top of Hibernate by using the JPA model: https://persistence.blazebit.com/documentation/1.6/core/manual/en_US/#recursive-ctes
In your case this would look like the following:
#CTE
#Entity
public class ResultCte {
#Id
Long parentId;
Long rootId;
int level;
}
CriteriaBuilder<Tuple> cb = criteriaBuilderFactory.create(entityManager, Tuple.class);
cb.withRecursive(ResultCte.class)
.from(Entity2.class, "e2")
.where("e2.id").in(idList)
.bind("parentId").select("e2.parent.id")
.bind("rootId").select("e2.id")
.bind("level").select("1")
.unionAll()
.from(Entity2.class, "e2")
.from(ResultCte.class, "cte")
.where("e2.id").eqExpression("cte.parentId")
.bind("parentId").select("e2.parent.id")
.bind("rootId").select("cte.rootId")
.bind("level").select("cte.level + 1")
.end()
.from(Entity1.class "a")
.from(ResultCte.class, "cte")
.where("a.id").eqExpression("cte.parentId")
.select("cte.rootId")
.select("min(a.time)")
Using JPA and need help with the same.
Current query looks as below
#Query("SELECT o FROM orders o " +
"WHERE (o.type = 'type1'... " +
" ) " +
" OR (o.type = 'type2' ...... " +
" ) "
)
Page<Order> getOrders(Pageable pageable);
to the above now I have to add another "OR" condition (type3 as below) for which I need to get only 1 record that match criteria i.e limit one only for this new OR condition.
Need to limit 1 for below criteria only
" OR (o.type = 'type3' ...... " +
" limit 1) "
how can I do that in JPA?
Unable to pass named parameters in #NamedNativeQuery in spring data jpa
my repo:
#Query(value = "select stat.desc as desc," +
" stat.priority as priority," +
" (case when sum(activeUser) is null then 0 else sum(activeUser) end) as activeUser," +
" (case when sum(totalUser) is null then 0 else sum(totalUser) end) as totalUser" +
" from lookup.user stat left outer join" +
" (" +
" select user.role as role, " +
" sum (case when user.STATUS = 'ACTIVE' then 1 else 0 end) as activeUser," +
" count(*) as totalUser," +
" user.group as group" +
" from Ctrl.user user" +
" where user.group =:userGroup " +
" and user.branch_code =:branchCode " +
" group by user.role,user.group" +
" ) as tbl on stat.role = tbl.role and stat.group = tbl.group" +
" where stat.group =:userGroup " +
" group by stat.desc, stat.priority" +
"", nativeQuery = true)
public List<com.cimb.dto.UserStatusSummary> getSummaryReport(#Param(value = "userGroup") String userGroup, #Param(value = "branchCode") String branchCode);
The underlying database is DB2
When I tried to access that method I am hitting following error.
DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.25.13
if I hard code those named parameters with values then it's working.
I can not use jpql as real queries have some subqueries in it, so I cant use JPQL
Edit Update
After some digging, I have found out that, the parameters I am passing are in the subquery, since JPA don't have subquery concept it's not injecting into named parameters which resulting in a syntax error.
Now how to work with Subqueries in JPA
Please help.
I wrote a SQL query which updates the record, in most cases it runs fine, but from yesterday it fails to update the row.I am currently working on Spring MVC based Web application, in which I need to perform the DML operation by calling update()method.
I am using JDBC template and in my update method i wrote this query.
It fetches the 947 records for January month 2018 and I already checked all records are unique.
I am here stuck, i am not able to find the duplication of record.I thought this exception occurred because of multiple record, but I think i am wrong, there is something which i am not able to identify.
Here is the query:
UPDATE SALARY_DETAIL_REPORT_012018 sd
SET sd.EMP_ID =
(SELECT e.emp_id from EMPLOYEE e
WHERE e.VERIFY_STATUS = 1
AND e.RELIEF_TYPE IS NULL
AND e.emp_code = to_char(sd.emp_code)
AND e.EMP_TYPE_ID!=03)
WHERE EXISTS
(SELECT e.emp_id from EMPLOYEE e
WHERE e.VERIFY_STATUS = 1
AND e.emp_code = to_char(sd.emp_code)
AND e.EMP_TYPE_ID!=03 AND e.RELIEF_TYPE IS NULL)
AND sd.EMP_ID IS NULL
AND sd.REFERENCE_ID LIKE '203-%'
and HERE is Java Code in my DAOImpl class
public void update(String tableSuffix, String regionId, String circleId) {
String tabName = "SALARY_DETAIL_REPORT_" + tableSuffix;
String q = "UPDATE " + tabName + " sd"
+ " SET sd.EMP_ID = (SELECT e.emp_id "
+ " from EMPLOYEE e WHERE e.VERIFY_STATUS = 1 AND e.RELIEF_TYPE IS NULL "
+ " AND e.emp_code = to_char(sd.emp_code) AND e.EMP_TYPE_ID!=03) "
+ " WHERE "
+ " EXISTS (SELECT e.emp_id from EMPLOYEE e WHERE e.VERIFY_STATUS = 1 "
+ " AND e.emp_code = to_char(sd.emp_code) AND e.EMP_TYPE_ID!=03 AND e.RELIEF_TYPE IS NULL) "
+ " AND sd.EMP_ID IS NULL";
if (circleId != null && !circleId.trim().equals("")) {
q += " AND sd.REFERENCE_ID LIKE '" + circleId + "-%' ";
} else {
q += " AND sd.REFERENCE_ID LIKE '" + regionId + "-%' ";
}
// System.out.println("q " + q);
MapSqlParameterSource param = new MapSqlParameterSource();
getNamedParameterJdbcTemplate().update(q, param);
}
Please suggest me the best solution
You need to find the rows that prevent your query from running.
Run this query:
SELECT sd.emp_code, COUNT(*) as cnt
FROM EMPLOYEE e
WHERE e.VERIFY_STATUS = 1 AND
e.RELIEF_TYPE IS NULL AND
e.emp_code = to_char(sd.emp_code) AND
e.EMP_TYPE_ID <> 03
GROUP BY sd.emp_code
HAVING COUNT(*) > 1;
This has the candidate problems. What can you do? The simplest thing is one of the problems:
Change the SELECT to SELECT MAX(sd.emp_code)
Change the WHERE with AND rownum = 1
Edit-
I'll add the use case to clear up the function of this.
The user will select two dates - a start date and an end date - these are then passed on and used to select the tables (each year has its own table). In one use case where the two given dates lie in the same year it's a simple query on that table alone.
However, if the two dates are different years I will need to join all tables (so 2011-2013 will be three tables connected, to search through) and thus, I want a dynamic fix to this. I know building up a query like below is against security - just thought something similar would work. As the system will get new tables each year I also dont want to have to manually add however many new queries for each case (2011-2016, 2014-2018, 2011-2019.. etc)
I have a question about whether it is possible to create a dynamic query as a String like below and then pass that through to service -> repository, and use that as a query?
for (int i = 0; i < yearCondition; i++) {
if (i == 0) {
query += "SELECT md.Device_ID, l.locationRef, " + reportRunForm.getStartDate() + " as 'From Date', "
+ reportRunForm.getEndDate() + " as 'To Date' "
+ "from mData.meterdata" + iDateStart.substring(0, 4)
+ " join MOL2.meters m on device_ID = m.meterUI "
+ "join MOL2.locations l on m.locationID = l.locationID "
+ "join MOL2.meterreg mr on m.meterID = mr.meterID "
+ "where mr.userID = ?1";
}
query += "UNION SELECT md.Device_ID, l.locationRef, " + reportRunForm.getStartDate() + " as 'From Date', "
+ reportRunForm.getEndDate() + " as 'To Date' "
+ "from mData.meterdata" + (Integer.parseInt(iDateStart.substring(0, 4))+i)
+ " join MOL2.meters m on device_ID = m.meterUI "
+ "join MOL2.locations l on m.locationID = l.locationID "
+ "join MOL2.meterreg mr on m.meterID = mr.meterID "
+ "where mr.userID = ?1";
}
I may have the wrong idea with how this works, and I know I could create and persist a query through entitymanager, but wanted to know whether doing it through the repository would be possible?
My thought was I'd build up the query like above, pass it through to service and then to repository, and bind it as value in #Query annotation but this doesn't seem possible. I'm likely approaching this wrong so any advice would be appreciated.
Thanks.
Edit -
Had a goof. Understand doing it at all like that is stupid, an approach to build up something similar is what I'm looking for that is still secure.
Maybe this annotations before your POJO can help
#org.hibernate.annotations.Entity(dynamicInsert = true)
for example two tables district and constituency ...
Dynamic query
query += "select *from constituency c where 1=1";
if(constituencyNumber!=null)
query +=" and c.constituency_number like '"+constituencyNumber+"%'";
query += " group by c.district_id";
OR
select *from constituency c where (c.constituency_number is null or c.constituency_number like '1%') group by c.district_id;