How to integrate variable in native sql query in Spring Data - sql

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

Related

How to use inbuild db functions, sub query and join in a single query using criteria builder in JPA

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)

how to get only first row of datatable with modified specific row value

I have query to just summary of total no of jobs running. now I just want some specific result if there is unique rows found like unique category id with assign job then ok with multiple record set. but no category found if is null then just only pass first record from datatable with modified text with 'ALL' as category name. can we achieve this result.
here is my query and some operations I'm doing with them.
string str = "";
DataTable dt = new DataTable();
str = "SELECT j.[JobID], p.[Id] As PreparedEmailID,p.[Title] AS 'PreparedEmailName',j.[CreatedOn],j.[CompletedOn],j.CategoryID,j.[SubscriberCount],j.[EmailsSent],c.[CategoryName] As SubscriberCategory,(SELECT TOP 1 [Message] FROM [LoggedMessages] WHERE [JobID] =j.[JobID] ORDER BY [LoggedMessageID] DESC) AS 'LoggedMessage',(SELECT [Name] FROM tbl_User_master u WHERE u.Id =j.UserID) As CreatedBy FROM [Jobs] AS j INNER JOIN [tbl_Email_master] AS p ON p.[Id] = j.[PreparedEmailID] INNER JOIN [tbl_User_master] AS u ON u.[Id]=j.[UserID] INNER JOIN tbl_Categories c ON c.Id = j.CategoryID OR (c.Id IS NOT NULL AND j.CategoryID IS NULL) where 1=1 ";
if (chk_date.Checked == true)
{
str += " and ( [CreatedOn] between '" + CommonLogic.Get_Date_From_String(txt_date_from.Text, 1);
str += "' and '" + CommonLogic.Get_Date_From_String(txt_date_to.Text, 2) + "' )";
}
if (string.IsNullOrEmpty(txttitle.Text.Trim()))
{
str += string.Empty;
}
else
{
str += " and p.Title like '%" + txttitle.Text.Trim() + "%'";
}
if (ddl_fromuser.SelectedItem.Text.ToString() == ".All")
{
str += string.Empty;
}
else
{
str += " and j.FromuserID = CONVERT(INT," + Convert.ToInt32(ddl_fromuser.SelectedValue.ToString()) + ")";
}
if (ddl_subcategories.SelectedItem.Text.ToString() == ".All")
{
str += string.Empty;
}
else
{
str += " and j.CategoryID = CONVERT(INT," + Convert.ToInt32(ddl_subcategories.SelectedValue.ToString()) + ")";
}
dt = obj.Get_Data_Table_From_Str(str);
if (dt.Rows.Count > 1)
{
dt.Rows[0]["SubscriberCategory"] = "ALL";
var topRows = dt.AsEnumerable().FirstOrDefault();
egrd.DataSource = topRows;
egrd.DataBind();
}
else
{
egrd.DataSource = dt;
egrd.DataBind();
}
ViewState["data"] = dt;
how ever this gives me error like no JobID found to this record set. whether it is still exists in record set.
please help me...
well I tried this solution but no success...……..
if (dt.Rows.Count > 1)
{
dt.Rows[0]["SubscriberCategory"] = "ALL";
var topRows = dt.AsEnumerable().GroupBy(j => j.Field<int>("JobID")).Select(j => j.First()).ToList();
egrd.DataSource = topRows;
egrd.DataBind();
}
it's gives me exception like DataBinding: 'System.Data.DataRow' does not contain a property with the name 'JobID'.
Just replace .ToList() with .CopyToDataTable() resolve my problem

find ordered list in hql by max different between values with max dates

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;

Spring query where in () is not working

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

objectdb select where query

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.