How to rewrite given query in jpql custom query? - mysql

I have a mysql query which look like this:
SELECT * FROM `HOST` WHERE `DATE_OF_SCAN` between
(SELECT subtime((Select max(`DATE_OF_SCAN`) from `HOST` ), '0 0:5:0'))
and
(Select max(`DATE_OF_SCAN`) from `HOST` );
which basically is returning hosts from range of max date in table and (max date - 5 min).
I'm trying to rewrite it in the jpql:
#Query("SELECT h FROM Host h WHERE h.date between "
+ "(SELECT subtime((Select max(ho.date) from Host ho ), 0 0:5:0)) "
+ "and (Select max(hos.date) from Host hos)")
public List<Host> findHosts();
but it is constantly throwing exception:
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: 0 near line 1, column 126 [SELECT h FROM com.iie.model.Host h WHERE h.date between (SELECT subtime((Select max(ho.date) from com.iie.model.Host ho ), 0 0:5:0)) and (Select max(hos.date) from com.iie.model.Host hos)]
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:47)
at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:79)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:276)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:180)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:119)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:214)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:192)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1537)
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:285)
finally. I've tried to pass the '0 0:5:0' as a parameter, but it throws an exception that this is not a proper Joda DateTime format.
The Host:
#Entity
#Table(name = "HOST")
public class Host {
#Id
#GeneratedValue
#Column(name = "HOST_ID")
private Long id;
#Column(name = "HOSTNAME")
private String hostname;
#Column(name = "IP")
private String ip;
#Column(name = "DATE_OF_SCAN")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime date;
public Host(Long id, String hostname, String ip, DateTime date) {
this.id = id;
this.hostname = hostname;
this.ip = ip;
this.date = date;
}
public Host(String hostname, String ip, DateTime date) {
this.hostname = hostname;
this.ip = ip;
this.date = date;
}
public Host() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public DateTime getDate() {
return date;
}
public void setDate(DateTime date) {
this.date = date;
}

this part is not valid SQL
SELECT h FROM Host h
I suggest changing to explicit column names
SELECT h.mycolumn FROM Host h

Related

Pagination with native query using alias in spring boot

I have a sql table named reporting_general and I want to use a complex native sql query in which I used SQL Aliases , for that purpose I implemented JPA Projection to map the columns, so I made an interface for that purpose, but I am getting this error.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'REPORTING_GENERAL WHERE REPORTING_GENERAL.ID > 0 AND CHANNEL in ('A', 'C') AND ' at line 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-j-8.0.31.jar:8.0.31]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-j-8.0.31.jar:8.0.31]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916) ~[mysql-connector-j-8.0.31.jar:8.0.31]
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:972) ~[mysql-connector-j-8.0.31.jar:8.0.31]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.6.14.Final.jar:5.6.14.Final]
Here is My Postman
SQL Table
Entity class
#Entity
#Table(name = "reporting_general")
#Data
public class ReportingGeneral implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int id;
#Column(name = "transaction_name")
public String transactionName;
public String username;
#Column(name = "contact_number")
public String contactNumber;
public String segment;
#Column(name = "user_type")
public String userType;
#Column(name = "primary_key")
public String primaryKey;
public String channel;
#Column(name = "response_code")
public String ResponseCode;
#Column(name = "request_time")
public Date requestTime;
#Column(name = "response_time")
public Date responseTime;
}
Interface used for JPA Projection (the atributes of this class are the aliases I've used in the query)
public interface ActiveAccountReport {
String getUserName();
String getContactNumber();
String getPrimaryKey();
String getMinRequestTime();
String getMaxRequestTime();
String getSuccess();
String getFailed();
String getTotalHits();
String getChannel();
}
Repository class
public interface ReportingGenRepo extends JpaRepository<ReportingGeneral, Integer> {
#Query(value = "SELECT REPORTING_GENERAL.USERNAME AS userName, " +
"ANY_VALUE (REPORTING_GENERAL.CONTACT_NUMBER ) AS contactNumber,ANY_VALUE (REPORTING_GENERAL.PRIMARY_KEY) AS primaryKey," +
"MIN( REQUEST_TIME ) AS minRequestTime ,MAX( REQUEST_TIME ) AS maxRequestTime, " +
"COUNT(IF ( RESPONSE_CODE = '1', 1, NULL )) AS success,COUNT(IF " +
"( RESPONSE_CODE != '1', 1, NULL )) AS failed,COUNT(*) AS totalHits,CHANNEL as channel" +
" FROM REPORTING_GENERAL WHERE " +
" REPORTING_GENERAL.ID > 0 AND CHANNEL in ?3 AND (REPORTING_GENERAL.REQUEST_TIME BETWEEN ?1 AND ?2)" +
"GROUP BY channel, username", nativeQuery = true)
public Page<ActiveAccountReport> getActiveAccountReportFilters(
LocalDateTime startDate,
LocalDateTime endDate,
List<Character> channel,
Pageable pagable);
}
Service Class
#Service
public class ReportingGenService {
#Autowired
private ReportingGenRepo reportingGenRepo;
public Page<ActiveAccountReport> paginatedActiveAccountReports(ActiveAccountRequest activeAccountRequest,
Integer page,Integer size) {
Pageable pageable = PageRequest.of(page,size);
Page<ActiveAccountReport> activeAccountReports = reportingGenRepo.getActiveAccountReportFilters(activeAccountRequest.getStartDate(),
activeAccountRequest.getEndDate(),activeAccountRequest.getChannel(),pageable);
return activeAccountReports;
}}
Controller Class
#RestController
#RequestMapping("/repo")
public class ReportingGenController {
#Autowired
private ReportingGenService reportingGenService;
#GetMapping("/get")
public Page<ActiveAccountReport> findAll(#RequestBody ActiveAccountRequest activeAccountRequest,
#RequestParam("page") Integer page, #RequestParam("size") Integer size){
return reportingGenService.paginatedActiveAccountReports(activeAccountRequest,page,size);
}
If you want to use Paging and native queries you must provide a countQuery.
IN your case:
#Query(value = "SELECT REPORTING_GENERAL.USERNAME AS userName, " +
"ANY_VALUE (REPORTING_GENERAL.CONTACT_NUMBER ) AS contactNumber,ANY_VALUE (REPORTING_GENERAL.PRIMARY_KEY) AS primaryKey," +
"MIN( REQUEST_TIME ) AS minRequestTime ,MAX( REQUEST_TIME ) AS maxRequestTime, " +
"COUNT(IF ( RESPONSE_CODE = '1', 1, NULL )) AS success,COUNT(IF " +
"( RESPONSE_CODE != '1', 1, NULL )) AS failed,COUNT(*) AS totalHits,CHANNEL as channel" +
" FROM REPORTING_GENERAL WHERE " +
" REPORTING_GENERAL.ID > 0 AND CHANNEL in ?3 AND (REPORTING_GENERAL.REQUEST_TIME BETWEEN ?1 AND ?2)" +
"GROUP BY channel, username",
countQuery = "SELECT count(*) FROM REPORTING_GENERAL WHERE " +
" REPORTING_GENERAL.ID > 0 AND CHANNEL in ?3 AND (REPORTING_GENERAL.REQUEST_TIME BETWEEN ?1 AND ?2)" +
"GROUP BY channel, username"
nativeQuery = true)

Trouble executing an JPQL query

I'm working with spring boot entity manger using JPQL with queries.
The following query is working correctly:
SELECT h, uh FROM Hour h, UserHour uh
But now I want to get a single result for which I use the query:
SELECT h FROM Hour h INNER JOIN UserHour uh WHERE uh.userId = 1
But then the results are zero, which is not expected.
But, when I use the SQL query:
SELECT * FROM hour
INNER JOIN user_hour
ON user_hour.hour_id = hour.hour_id
WHERE user_hour.user_id = '1'
I get the result I want.
Please help me out.
EDIT:
List<Object> result = entityManager.createQuery(
"select distinct hr " +
"from Hour hr " +
"join hr.users hu " +
"where hu.id = :userID")
.setParameter( "userID", 1)
.getResultList();
System.out.println(result);
User Entity:
package com.timely.backend.models;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "USER")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String fullname;
private String email;
private String creation_date;
// user roles
#ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
private Set<Role> roles;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "user_hour",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "hourId")
)
private List<Hour> hours = new ArrayList<>();
public User() {
}
public User(String username, String password, String fullname, String email, String creation_date) {
this.username = username;
this.password = password;
this.fullname = fullname;
this.email = email;
this.roles = getRoles();
this.creation_date = creation_date;
}
//If user is admin
public boolean isAdmin() {
return roles.contains(Role.ADMIN);
}
//region Getters & Setters
public void setId(int id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setFullname(String fullName) {
this.fullname = fullName;
}
public void setEmail(String email) { this.email = email; }
public void setRoles(Set<Role> roles) { this.roles = roles; }
public void setCreation_date(String creation_date) { this.creation_date = creation_date; }
public int getId() { return id; }
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getFullname() {
return fullname;
}
public String getEmail() { return email; }
public Set<Role> getRoles() { return roles; }
public String getCreation_date() { return creation_date; }
//endregion
}
UserHour Entity:
package com.timely.backend.models;
import javax.persistence.*;
#Entity
#Table(name = "user_hour")
public class UserHour {
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getHourId() {
return hourId;
}
public void setHourId(int hourId) {
this.hourId = hourId;
}
public UserHour(int userId, int hourId) {
this.userId = userId;
this.hourId = hourId;
}
public UserHour(){
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int userId;
private int hourId;
}
Hour Entity:
package com.timely.backend.models;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(name = "HOUR")
public class Hour {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int hourId;
private String date;
private String startTime;
private String endTime;
public Hour(int hourId, String date, String startTime, String endTime) {
this.hourId = hourId;
this.date = date;
this.startTime = startTime;
this.endTime = endTime;
}
public Hour(){
}
#ManyToMany(mappedBy = "hours")
private List<User> users = new ArrayList<>();
public int gethourId() {
return hourId;
}
public void sethourId(int hourId) {
this.hourId = hourId;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
}
MySQL query working:
SELECT id, date, start_time, end_time FROM hour
JOIN user_hour
ON user_hour.hour_id = hour.hour_id
WHERE user_hour.user_id = '1'
Problem:
User Table:
UserHour Table:
Hour Table:

The boolean value of the objects coming from a Query is wrong

I have this activity_company table which includes an activity and company. I am trying to order the result of this query by modified_date and id. And in the activity table there is a boolean field such as shared. All the shared values are false in the database but after this query the resulted objects' shared fields are displayed as true even if they are still false in the DB. Any idea what causes this situation ?
SELECT activity.*
FROM activity
INNER JOIN activity_company ON activity.id=activity_company.activity_id
WHERE activity_company.company_id=1
ORDER BY activity.modified_date, activity.id
This is the activity class;
#Entity
public class Activity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(columnDefinition = "TEXT")
private String param;
private Date createdDate;
private int activityType;
private long classNameId;
private long classPK;
private Date modifiedDate;
private boolean shared;
#ManyToOne
private User creatorUser;
#ManyToOne
private Company creatorCompany;
#OneToMany(mappedBy = "activity")
private List<ActivityCompany> activityCompanies = new ArrayList<ActivityCompany>();
#OneToMany(mappedBy = "activity")
private List<ActivityAttachment> activityAttachments;
public Activity(String param, User user, int activityType) {
this.param = param;
this.createdDate = new Date();
this.activityType = activityType;
this.creatorUser = user;
this.modifiedDate = new Date();
}
and activitycompany;
#Entity
public class ActivityCompany {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private Activity activity;
#ManyToOne
private Company company;
public Activity getActivity() {
return activity;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Long getId() {
return id;
}
}

how to write this query using hql

Thi is my query:
SELECT d.fullName,d.doctorId,d.speciality, t.hospital, t.date, t.time
FROM Doctor d, TimeTable t
WHERE d.doctorId = t.doctorId and d.fullName = 'Subash Nisam' and t.date = '2017.03.02'
ORDER BY t.date;
I've two tables->Doctor and TimeTable
#Entity
public class TimeTable {
private int timeTableId;
private String time;
private String date;
private String hospital;
private Doctor doctor;
#Id
#GeneratedValue(strategy = AUTO)
public int getTimeTableId() {
return timeTableId;
}
public void setTimeTableId(int timeTableId) {
this.timeTableId = timeTableId;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getHospital() {
return hospital;
}
public void setHospital(String hospital) {
this.hospital = hospital;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "doctorId", nullable = false)
public Doctor getDoctor() {
return doctor;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
}
//////////////////////////////////////////
#Entity
public class Doctor {
private int doctorId;
private String fullName;
private String regNo;
private String designation;
private String speciality;
private String address;
private String contactNo;
private String email;
private String workingTime;
private String password;
private String branch;
---------------------------------------------
#Id
#GeneratedValue(strategy = AUTO)
public int getDoctorId() {
return doctorId;
}
#OneToMany(cascade = CascadeType.ALL, mappedBy = "doctor")
public Set<TimeTable> getTimeTables() {
return timeTables;
}
public void setTimeTables(Set<TimeTable> timeTables) {
this.timeTables = timeTables;
}
}
I want to write my query using hql. hope your help.
Try this syntax:
select d.fullName, d.doctorId, d.speciality, t.hospital, t.date, t.time
from Doctor as d
inner join d.timeTables t
where d.fullName = 'Subash Nisam' and t.date = '2017-03-02'
Try this one
select Doctor.fullname, Doctor.doctorId, Doctor.speciality, TimeTable.hospital, TimeTable.date, TimeTable.time from Doctor inner join TimeTable on Doctor.doctorId =TimeTable.doctorId where Doctor.fullname='Subash' and Timetable.date='2017-03-02' order by Timetable.date;
#Tim Biegeleisen------->
Here is the output
select
doctor0_.doctorId as doctorId1_3_0_,
timetables1_.timeTableId as timeTabl1_5_1_,
doctor0_.address as address2_3_0_,
doctor0_.branch as branch3_3_0_,
doctor0_.contactNo as contactN4_3_0_,
doctor0_.designation as designat5_3_0_,
doctor0_.email as email6_3_0_,
doctor0_.fullName as fullName7_3_0_,
doctor0_.password as password8_3_0_,
doctor0_.regNo as regNo9_3_0_,
doctor0_.speciality as special10_3_0_,
doctor0_.workingTime as working11_3_0_,
timetables1_.date as date2_5_1_,
timetables1_.doctorId as doctorId5_5_1_,
timetables1_.hospital as hospital3_5_1_,
timetables1_.time as time4_5_1_
from
Doctor doctor0_
inner join
TimeTable timetables1_
on doctor0_.doctorId=timetables1_.doctorId
where
doctor0_.fullName='Subash Nisam'
and timetables1_.date='2017.03.02'
It gives all result of the doctor such as fullname, password, address...
but I want to get fullName and doctorId from doctor table and other data from timetable table.

Remove an item if it appears more than 10times and store the new one

I want to store users 10 previous passwords so that He/she do not use old passwords. For this I have created a table with 3 columns:
id
password
userId
Now if person forgot his password 11th time and do update password then it should remove its 1st old password and hence store new one. What would be the sql query for that?
I have first checked the count of useridentity which is working perfectly:
SELECT userIdentity, COUNT(userIdentity) FROM passwordhistory;
Now if count >10 then I want to remove the row with minimum id associated with it using.
DELETE FROM passwordhistory
WHERE id = (SELECT MIN(id)
FROM passwordhistory where userIdentity in
(SELECT userIdentity, COUNT(userIdentity)
FROM passwordhistory
)
)
But this is incomplete as how to delete userIdentity with count>10.
PasswordHistory.java
package com.tcs.webrtc.model;
import java.io.Serializable;
#Entity
#Table(name="passwordhistory")
public class PasswordHistory implements Serializable{
/**
*
*/
private static final long serialVersionUID = 2621325802545502360L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#NotNull
private String userIdentity;
#NotNull
private String password;
public String getUserIdentity() {
return userIdentity;
}
public void setUserIdentity(String userIdentity) {
this.userIdentity = userIdentity;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Since you use mysql, you should create a list of the id to delete, then remove them:
Create the list:
Session session=sessionFactory.getCurrentSession();
String queryToCheckPassword="
SELECT MIN(id)
FROM passwordhistory where userIdentity in
(SELECT userIdentity
FROM passwordhistory
group by userIdentity
having COUNT(userIdentity) >10
)
";
List listToDel = session.createSQLQuery(queryToCheckPassword).list();
return listToDel .size()>0?true:false;
Remove by id (this is where the java man comes);
<for each item in listToDel >
delete from passwordhistory where id = :id