Spring Data, JPQL, Group by month of a date column(type LocalDate) - postgresql

I have to get total price in month from a date yy-mm-dd with jpql query but I can't do it.
#Query(value = "select new com.talan.food.dto.MonthIncomes( function('date_format',date,'%Y-%m'),SUM(p.price)) from Reservation p group by function('date_format',p.date,'%Y-%m')" )
public List<MonthIncomes> getIncomeByMonth();
And in the table of entity I have:
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private double price;
#ManyToOne #JoinColumn(name="userId" )
public User user;
private LocalDate date;
private boolean confirmed;
}
And I will put the result in the class :
public class MonthIncomes {
private LocalDate date ;
private double price;
public MonthIncomes (LocalDate date, double price) {
this. date= date;
this.price = price;
}
}

You could something like this in your query
SELECT p.date as date ,
SUM(p.price) as price
FROM reservation p
WHERE p.date >= '2022-01-01'
GROUP BY
EXTRACT(month from p.date)
depending on the amount of yours you have to go back you would have to change the extract statement a bit. Nevertheless your problem looks like something that you could approach with the extract function
https://www.postgresqltutorial.com/postgresql-date-functions/postgresql-extract/

i resolve the problem by using this syntaxe:
#Query(value = "select new com.food.dto.MonthIncomes(EXTRACT(month from p.date),SUM(p.price)) from Reservation p group by EXTRACT(month from p.date) ORDER BY EXTRACT(month from p.date)")
public List<MonthIncomes> getIncomeByMonth();

Related

How to use date_format when using JPQL/JPA to do the sum group by month from column date

I have to get the total price in month from a date(LocalDate) yy-mm-dd with jpql query but i can't do it
with jpql with function : function('date_format',p.date,'%Y-%m')
//in the table of entity i have:
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private double price;
#ManyToOne #JoinColumn(name="userId" )
public User user;
private LocalDate date;
private boolean confirmed;}
the class where i will put the result
public class MonthIncomes {
private LocalDate date ;
private double price;
public MonthIncomes (LocalDate date,double price){
this. date= date;
this.price = price;
}
//what i do in repository
public interface ReservationRepo extends JpaRepository<Reservation, Long> {
#Query(value = "select new com.food.dto.MonthIncomes( function('date_format',date,'%Y-%m'),SUM(p.price)) from Reservation p group by function('date_format',p.date,'%Y-%m')" )
public List<MonthIncomes> getIncomeByMonth();}`

JPA - select where max date

I have the below query which returns a list of bank accounts.
#Query("SELECT bd FROM assign_iban_entity aie INNER JOIN aie.bankData bd WHERE aie.agreementFileId = ?1")
List<BankAccountEntity> findAllBankAccountByAgreementFileId(String agreementFileId);
My entity:
#Entity(name = "bank_data_entity")
public class BankAccountEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String bankDataId;
private Date createdDate;
}
I want to change the query to return only one BankAccountEntity who has the greatest createdDate.

How to return a count column not exists in table by JPA

I want find a way to get extra column that count my records and return it in 1 mapping entity with extra filed.
I tried #transient on field but it will not return value when query.
Then I remove #transient but get an exception when save.
Also I tried #Formula but received null pointer exception.
Here's my repository code:
#Query(value = "select id,account,session_id,create_time,count from query_history a join " +
"(select session_id sessionId,max(create_time) createTime,count(*) count from query_history group by session_id) b " +
"on a.session_id = b.sessionId and a.create_time = b.createTime where account = ?1 order by create_time desc",
countQuery = "select count(distinct(session_id)) from query_history where account = ?1",
nativeQuery = true)
Page<QueryHistory> findByNtAndGroupBySessionAndAction(String account, Pageable pageable);
entity code:
#Entity
#Table(name = "query_history")
#Data
public class QueryHistory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String account;
#Column
private Long sessionId;
#Column
private long createTime;
#Transient
private Integer count;
}
Sorry about my English and thanks a lot for any advice.
I solved the problem by projections spring-data-projections, in fact I tried this before but in my sql:
select id,account,session_id,create_time,count
which should be:
select id,account,session_id sessionId,create_time createTime,count
PS:
projection interface:
public interface QueryHistoryWithCountProjection {
Long getId();
String getAccount();
Long getSessionId();
long getCreateTime();
Integer getCount();
}

How do I use JPA to select the record with the closest date?

Let's say I have a collection of Rates that all inherit from an AbstractRate
#MappedSuperclass
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "name")
#Table(name = "rates")
public abstract class AbstractRate {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Column(precision = 13, scale = 4)
private BigDecimal value;
#OneToOne
private EffectiveDate effectiveDate;
...
}
And, that all have an EffectiveDate:
#Entity
public class EffectiveDate {
#Id
private LocalDateTime date;
...
}
(I acknowledge that a separate date object is a little over-kill for this model, but it's allowing me to bind multiple rates and other figures in the database.)
Now, I'd like to get a specific Rate, say SalaryRate, that is effective as of a certain date. I can do something like
salaryRateRepository.findByEffectivedate(
effectiveDateRepository.findTopByDateLessThanEqualOrderByDateDesc(sampleDate)
);
This should effectively give me a the MAX(date) and its matching Rate. Is this the right way to query these things? Some posts suggest
As an additional option, I have Querydsl setup and the repositories extend QuerydslPredicateExecutor. However, I'm not really familiar with how Querydsl's syntax works.
I think all is OK with findTopByDateLessThanEqualOrderByDateDesc(sampleDate).
Another variants should be:
#Query(value = "select * from effective_date ed where ed.date <= ?1 order by ed.date desc limit 1", nativeQuery = true)
EffectiveDate findEffectiveDate(LocalDateTime dateTime);
or
Predicate p = QEffectiveDate.effectiveDate.date.loe(sampleDate);
Pageable page = new PageRequest(0, 1, new Sort(Sort.Direction.DESC, "date"));
//...
EffectiveDate effectiveDate = effectiveDateRepository.findAll(p, page).getContent().stream().findFirst().orElse(null);
(not tested...)

How to find by date from timestamp column in JPA criteria?

I want to find a record by date. In entity and database table, datatype is timestamp. I used Oracle database.
#Entity
public class Request implements Serializable {
#Id
private String id;
#Version
private long version;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATION_DATE")
private Date creationDate;
public Request() {
}
public Request(String id, Date creationDate) {
setId(id);
setCreationDate(creationDate);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
}
in mian method
public static void main(String[] args) {
RequestTestCase requestTestCase = new RequestTestCase();
EntityManager em = Persistence.createEntityManagerFactory("Criteria").createEntityManager();
em.getTransaction().begin();
em.persist(new Request("005",new Date()));
em.getTransaction().commit();
Query q = em.createQuery("SELECT r FROM Request r WHERE r.creationDate = :creationDate",Request.class);
q.setParameter("creationDate",new GregorianCalendar(2012,12,5).getTime());
Request r = (Request)q.getSingleResult();
System.out.println(r.getCreationDate());
}
In Oracle database record is,
ID CREATION_DATE VERSION
006 05-DEC-12 05.34.39.200000 PM 1
Exception is,
Exception in thread "main" javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.throwNoResultException(EJBQueryImpl.java:1246)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:750)
at com.ktrsn.RequestTestCase.main(RequestTestCase.java:29)
The DB type is TIMESTAMP and not DATE, meaning you store exact times.
When using new GregorianCalendar(2012,12,5).getTime() you are quering timestamps that match the given date at 00:00:00.000 and that doesn't exist in your DB
You should either change the DB to store dates instead of timestamps or change your query.
JPA 2 got YEAR, MONTH and DAY functions so you can
SELECT WHERE YEAR(yourdate) = YEAR(dbdate) AND MONTH(yourdate) = MONTH(dbdate) and DAY(yourdate) = DATE(dbdate)
In Criteria API you can do something like this:
Expression<Integer> yourdateYear = cb.function("year", Integer.class, yourdate);
Expression<Integer> yourdateMonth = cb.function("month", Integer.class, yourdate);
Expression<Integer> yourdateDay = cb.function("day", Integer.class, yourdate);
Then combine them with the AND expression and do the same for the date field in db and compare them.
The SIMPLEST WAY to compare date of two datetimes
compare two date and ignore time
WHERE DATE(dbdDate) = DATE(yourDate)
You can use the native query in the jpql.
Example(SQL server):
select table from table where convert(date,mydate)=:date_colum