I am trying to query faculties that have 3 subjects mysql statement is as the following
select * from faculty_subject where subject_id in(1 and 3 and 2);
where 1, 2, 3 are subject ids. I only want courses that have all these subjects so that reason I am using and. But I do not why my spring query is not working. I tried different ways but it's returning faculties with the first subject id in this case 1. Here is my spring query
#Query(value = "select * from faculty_subject where subject_id in(?#{[0]} and ?#{[1]} and ?#{[1]})", nativeQuery = true)
List<FacultySubject> getFacultyBySubjects(long subjectTop, long subjectMid, long subjectBottom);
another one that did not work
#Query(value = "select * from faculty_subject where subject_id in(?1 and ?2 and ?3)", nativeQuery = true)
List<FacultySubject> getFacultyBySubjects(long subjectTop, long subjectMid, long subjectBottom);
another query
#Query(value = "select * from faculty_subject where subject_id in(:#{#subjectTop} and :#{#subjectMid} and :#{#subjectBottom})", nativeQuery = true)
List<FacultySubject> getFacultyBySubjects(#Param("subjectTop") long subjectTop,
#Param("subjectMid") long subjectMid,
#Param("subjectBottom") long subjectBottom);
Entity
#Entity
public class FacultySubject {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private long facultyId;
private int subjectId;
public FacultySubject(long facultyId, int subjectId) {
this.facultyId = facultyId;
this.subjectId = subjectId;
}
public FacultySubject() {
}
... getters and setters
#Query(value = "select * from faculty_subject where subject_id in(?1 , ?2 , ?3) group by faculty_id having count(*)==3", nativeQuery = true)
List<FacultySubject> getFacultyBySubjects(long subjectTop, long subjectMid, long subjectBottom);
Related
I know that BeanPropertyRowMapper<>() can wrap fields comparing database fields to Class fields by name.
But why when I'm using keyword "AS" i get an error.
jdbcTemplate code
public Book showBook(int id) {
return jdbcTemplate.query("SELECT books.id , books.name, books.author, books.year, books.people_id as peopleId, people.id as personId, people.name as personName FROM books LEFT JOIN people ON books.people_id = people.id WHERE books.id = ?",
new Object[]{id}, new BeanPropertyRowMapper<>(Book.class))
.stream().findAny().orElse(null);
}
Class fields
private int id;
#NotEmpty (message = "Name should not be empty")
#Size (min = 2, max = 255, message = "Name should be correct")
private String name;
#NotEmpty (message = "Field author should not be empty")
#Size (min = 2, max = 255, message = "Field author should be correct")
private String author;
#Min(value = 0)
private int year;
private int peopleId;
private int personId;
private String personName;
Tables
#Data
#Entity
#Table(name = "A")
class A {
private Long id;
private Long bId;
}
#Data
#Entity
#Table(name = "B")
class B {
private Long id;
#Enumerated(EnumType.STRING)
private Status status;
}
enum Status {
NEW,
VALIDATED,
ARCHIVE
}
I have a following native query
#Query(value = "SELECT cast(a.id as varchar) FROM a
INNER JOIN b on a.id = b.id
WHERE a.id = :id AND
b.status = 'NEW'", // here I need smth like b.status = '" + Status.NEW + "' ",
nativeQuery = true)
Set<UUID> findIdByStatuses(#Param UUID id)
Instead of b.status = 'NEW', I need smth like
b.status = '" + Status.NEW + "' ",
to get a compile error when name of Status changes. But it is not working like this.
And the question is how to reach that desirable concatenation inside of native query without method argumetns
I am trying to use few postgres inbuild functions, sub query and join in a single query in JPA where the result set (List<CampaignDTO>) is different from the actual entity (Campaign). I could achieve this by using native query and result transformation by "alias to bean".
Due to the deprecation I wanted to avoid the approach. Is there any way to achieve it using the criteria builder?
Here is the query:
select
"table1"."attemptedDate" "attemptedDate",
coalesce("table2"."messageAttempted", 0) "messageAttempted",
coalesce("table2"."messageSuccess", 0) "messageSuccess",
coalesce("table2"."messageFailure", 0) "messageFailure"
from
(
select
distinct generate_series(date '2020-11-10', date '2020-11-17', '1 day') "attemptedDate"
from
campaign) as "table1"
full join (
select
campaign_date "attemptedDate",
sum(coalesce(attempted_count, 0)) "messageAttempted",
sum(coalesce(delivered_count, 0)) "messageSuccess",
sum(coalesce(failed_count, 0)) "messageFailure"
from
campaign
where
channel = 'abc'
and campaign_date between '2020-11-10' and '2020-11-17'
group by
1) as "table2" on
"table1"."attemptedDate" = "table2"."attemptedDate"
order by
"attemptedDate"
Entity Class:
#Entity
#Table(name = "campaign")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Campaign{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name = "channel", nullable = false)
private String channel;
#Column(name = "attempted_count", nullable = false)
private Integer attemptedCount;
#Column(name = "delivered_count", nullable = false)
private Integer deliveredCount;
#Column(name = "failed_count", nullable = false)
private Integer failedCount;
#Column(name = "campaign_date", nullable = false)
private Date campaignDate;
}
DTO Class:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class CampaignDTO{
private Date attemptedDate;
#Builder.Default
private Integer messageAttempted = 0;
#Builder.Default
private Integer messageSuccess = 0;
#Builder.Default
private Integer messageFailure = 0;
}
Or is there any way to avoid deprecation while using transformation?
You will have to restructure the query or focus it in another way to implement it with criteriabuilder, since among other things it does not allow a query in the From clause.
Regarding the functions you can use them using the criteriabuilder function method (CriteriaBuilder function method)
I have a table in postgres
CREATE TABLE employer_visit(
employer_id INTEGER REFERENCES employer,
visit_counter INTEGER NOT NULL, -- counter on current date
visit_before_date_total_counter INTEGER NOT NULL, -- total, since service has started
date DATE,
PRIMARY KEY(employer_id, date)
);
I need to find top employers by visits from last 30 days - (ordered list of employer_visit by diff between visit_before_date_total_counter in last record and last record 30 days ago)
I have tried this hql query
Query<EmployerVisit> query = getSession().createQuery(
"SELECT ev FROM EmployerVisit ev " +
"WHERE ev.employerVisitId.date = (SELECT MAX (groupedEv.employerVisitId.date) FROM EmployerVisit groupedEv " +
"WHERE groupedEv.employerVisitId.employerId = ev.employerVisitId.employerId) " +
"AND " +
"ev.employerVisitId.date = (SELECT MAX (groupedEv2.employerVisitId.date) < :date FROM EmployerVisit groupedEv2 " +
"WHERE groupedEv2.employerVisitId.employerId = ev.employerVisitId.employerId) " +
"ORDER BY (groupedEv.visitCounter + groupedEv.visitBeforeDateTotalCounter) - (groupedEv2.visitCounter + groupedEv2.visitBeforeDateTotalCounter) DESC"
).setMaxResults(size).setParameter("date", calendar.getTime());
But it falls with
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'groupedEv.visitCounter'
Becouse the table groupedEv doesn't exist after ORDER BY
It is possible to use depricated SqlQuery for this case in hibernate but I prefere hql, please help, thanks.
UPDATE! - Entity and EmbeddedId Class without setters and getters
#Entity
#Table(name = "employer_visit")
public class EmployerVisit {
#EmbeddedId
private EmployerVisitId employerVisitId;
#Column(name = "visit_counter")
private Integer visitCounter;
#Column(name = "visit_before_date_total_counter")
private Integer visitBeforeDateTotalCounter;
public EmployerVisit() {
employerVisitId = new EmployerVisitId();
visitCounter = 0;
visitBeforeDateTotalCounter = 0;
}
}
#Embeddable
public class EmployerVisitId implements Serializable {
#Column(name = "employer_id")
private Integer employerId;
#Column(name = "date")
private Date date;
public EmployerVisitId() {
}
}
This is the Answer
Query<Object> query = getSession().createQuery(
"SELECT ev, SUM(ev.visitCounter) AS counter FROM EmployerVisit AS ev " +
"WHERE ev.employerVisitId.date > :date " +
"GROUP BY ev.employerVisitId.employerId, ev.employerVisitId.date " +
"ORDER BY counter DESC").setMaxResults(size).setParameter("date", calendar.getTime());
List<EmployerVisitDto> top = new ArrayList<>();
for (Object result : query.list()) {
Object[] dividedResult = (Object[]) result;
EmployerVisit employerVisit = (EmployerVisit) dividedResult[0];
EmployerVisitDto employerVisitDto = getEmployer(employerVisit.getEmployerId()).toEmployerVisitDto();
employerVisitDto.setPeopleVisited(((Long) dividedResult[1]).intValue());
top.add(employerVisitDto);
}
return top;
I attempt to select some instance using where clause
public static List<RSSItem> getRSSItem(int x1, int x2) {
EntityManagerFactory emf = DBHandler.getEmf();
EntityManager em = DBHandler.getEm(emf);
String query =
"SELECT items FROM RSSItem items "
+ "WHERE items.id <= :x1 AND "
+ "items.id >= :x2";
List<RSSItem> results =
(List<RSSItem>) em.createQuery(query).
setParameter("x1", x1).
setParameter("x2", x2).
getResultList();
return results;
}
the RSSItem attributes :
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
String title;
String link;
String description;
String pubdate;
String content;
HashMap<String, Integer> keyword = new HashMap();
HashMap<String, Integer> keywordBefore = new HashMap();
// TreeMap <String, Integer> keyword = new TreeMap();
String feed;
the problem is it always return a list with 0 size. what's wrong with my select query?
With the values x1 = 1 and x2 = 500, the query turns into...
SELECT items FROM RSSItem items
WHERE items.id <= 1
AND items.id >= 500
Since no id's are less or equal to 1 and greater or equal to 500 at the same time, the query will give no hits. What you want is probably;
String query =
"SELECT items FROM RSSItem items "
+ "WHERE items.id >= :x1 AND "
+ "items.id <= :x2";
...which with your example data will find all id's between 1 and 500, inclusive.