I am using PostgreSQL database & JPA. Here is my user table
CREATE TABLE users
(
id integer NOT NULL DEFAULT nextval('userseq'::regclass),
firstname character varying(64) ,
middlename character varying(64),
lastname character varying(64),
birthdate timestamp with time zone,
)
Query query = em
.createQuery(
"SELECT users FROM Users users WHERE user.birthdate =:a")
.setParameter("a",18)
.setParameter("b",25);
query.getResultList();
I want get all user whose age in between 18-25. Please complete my above JPA query
Use Between operator, fix to user.birthdate to users.birthdate at first.
Calendar cal_1 = Calendar.getInstance();
cal_1.add(Calendar.YEAR, -18);
Date a = cal_1.getTime();
Calendar cal_2 = Calendar.getInstance();
cal_2.add(Calendar.YEAR, -25);
Date b = cal_2.getTime();
query.setParameter("a", a);
query.setParameter("b", b);
SELECT users FROM Users users WHERE users.eventsDate BETWEEN :a AND :b
Example : x BETWEEN :min AND :max. Reference here
JPQL is lacking in date operators. In SQL you'd write something like:
SELECT age(TIMESTAMPTZ '1999-01-01') BETWEEN INTERVAL '18' YEAR AND INTERVAL '25' YEAR;
but you can't do that in JPQL as far as I can tell. BETWEEN is supported in JPQL, so I'd convert the date parameters a and b to java.util.Date using java.util.Calendar, then use:
SELECT users FROM Users users WHERE user.birthdate BETWEEN :a AND :b
Related
I am migrating a DB. In old DB we use some stored procedures - SP which we want to get rid off in new DB. Simply we want to use plain java query instead of a SP. We will call the query from our java spring boot app.
Here is the SP :
CREATE OR REPLACE PROCEDURE public.spfetchowner(
owner integer,
optype integer,
INOUT p_refcur refcursor)
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
OPEN p_refcur FOR
SELECT
z.owner_num,
COALESCE(op_type_num, optype) AS op_type_num,
ad.sunday, ad.monday, ad.tuesday, ad.wednesday, ad.thursday, ad.friday, ad.saturday
FROM (SELECT owner AS owner_num) AS z
LEFT OUTER JOIN owner_details AS ad
ON z.owner_num = ad.owner_num AND op_type_num = optype;
END;
$BODY$;
ALTER PROCEDURE public.spfetchowner(integer, integer, refcursor)
OWNER TO postgres;
My DB table details :
owner_num integer NOT NULL,
op_type_num integer NOT NULL,
sunday numeric(5,3),
monday numeric(5,3),
tuesday numeric(5,3),
wednesday numeric(5,3),
thursday numeric(5,3),
friday numeric(5,3),
saturday numeric(5,3),
CONSTRAINT pk_owner_details PRIMARY KEY (owner_num, op_type_num)
This is my java repository method to fetch details from owner_details
#Query(nativeQuery = true,
value = "I need the proper equivalent query from the SP here")
OwnerDetails fetchOwnerDetailsByOwnerNumAndOpType(
#Param("ownerNum") Integer owner,
#Param("typeNum") Integer type );
I am unable to form the query from the SP that I need to use in repo method. Can someone help me out here on the query formation part. Simple select is working but I would need the select query as framed in the SP with the joins and then how to use the same in my repo method.
When specifying the parameters to your query (#Query) you basically have 2 options
Option 1 (using named parameters)
#Query(nativeQuery = true,
value = "SELECT
z.owner_num,
COALESCE(op_type_num, optype) AS op_type_num,
ad.sunday, ad.monday, ad.tuesday, ad.wednesday, ad.thursday, ad.friday, ad.saturday
FROM (SELECT :ownerNum AS owner_num) AS z
LEFT OUTER JOIN owner_details AS ad
ON z.owner_num = ad.owner_num AND op_type_num = :typeNum")
OwnerDetails fetchOwnerDetailsByOwnerNumAndOpType(
#Param("ownerNum") Integer owner,
#Param("typeNum") Integer type );
or option 2 (using ordinal numbers preceded by a ?)
#Query(nativeQuery = true,
value = "SELECT
z.owner_num,
COALESCE(op_type_num, optype) AS op_type_num,
ad.sunday, ad.monday, ad.tuesday, ad.wednesday, ad.thursday, ad.friday, ad.saturday
FROM (SELECT ?1 AS owner_num) AS z
LEFT OUTER JOIN owner_details AS ad
ON z.owner_num = ad.owner_num AND op_type_num = ?2")
OwnerDetails fetchOwnerDetailsByOwnerNumAndOpType(
Integer owner,
Integer type );
In Data base , createdDt is storing formated like:
15-01-20 10:43:20.394000000 AM
I am passing "created" as dd-mm-yyyy
I want to take the matching date from the table(without comparing time)
#Query("SELECT p FROM ABC p WHERE ( COALESCE(:created) is null or p.createdDt = :created) order by p.createdDt desc")
List<ABC> filterABC(#Param("created") Date created);
How to parse the date within query ?
You could try to use native query using specific DBMS stuff to extract date part.
#Query(value = "SELECT * from ABC where DATE_FORMAT(createdDt, '%d-%m-%Y') = ?1", nativeQuery = true)
List<ABC> filterABC(Date created);
DATE_FORMAT is MySQL specific function. Use the appropriate date function in accordance with your DBMS
I am using HQL to get the data inserted exact 21 days from now. Here is my Code
Query queryThreeWeek = session.createQuery("from Users where createdDate = CURDATE()-21");
List<Users> userDetailsThreeWeekList = queryThreeWeek.list();
I can not use createSQLQuery.
Right now I am not getting any data, but there is data for the date 2016-06-20. And that is because of the month changed because when I used CURDATE()-7 I got the correct data of the date 2016-07-04.
The calculation for dat is like;
2016-07-11 - 7 = 20160704
2016-07-11 - 21 = 20160690
I also Tired using INTERVAL which is for native sqlQuery. Here is my code for using INTERVAL in HQL:
Query queryThreeWeek = session.createQuery("from Users where createdDate = DATE( DATE_SUB( NOW() , INTERVAL 21 DAY ) )");
List<Users> userDetailsThreeWeekList = queryThreeWeek.list();
Also tried
Query queryThreeWeek = session.createQuery("from Users where createdDate = DATE( DATE_SUB( CURDATE() , INTERVAL 21 DAY ) )");
List<Users> userDetailsThreeWeekList = queryThreeWeek.list();
but it is giving me exception like: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: 21.
So what can I use instead of subtracting the day like this: CURDATE()-21? in HQL only
I have solved the issue by using one native SQL query which can get me the exact date.
Query sub3Week = session.createSQLQuery("select DATE( DATE_SUB( CURDATE() , INTERVAL 21 DAY ) ) from dual");
List<Date> sub3WeekList = sub3Week.list();
And then I use this data in the HQL query like this:
Query queryThreeWeek = session.createQuery("from Users where createdDate = :createdDate");
queryThreeWeek.setParameter("createdDate", sub3WeekList.get(0).toString());
List<Users> userDetailsThreeWeekList = queryThreeWeek.list();
You can use date_Sub in a native SQL query (not a HQL query!):
"from Users where createdDate = DATE( DATE_SUB( NOW() , INTERVAL 21 DAY ) )"
The solution with HQL is quite simple:
final long time = System.currentTimeMillis() - java.time.Duration.ofDays(21).toMillis();
final javax.persistence.Query query = entityManagerOrSession.createQuery(
"SELECT x FROM users x WHERE x.createddate> :time");
query.setParameter("time", new java.sql.Timestamp(time));
I am trying to pull information from a table where the current date is between the first and last day of any given month.
I am getting a runtime error "Errors in named queries: Department.byDate"
I am providing you with what code I think could be causing the problem, if any additional code is needed please let me know in a comment.
My named query which looks like this:
#NamedQuery(name="Department.byDate", query="select * from department where date >= :first AND date <= :last")
I am using this named query in my DAO in a method which looks like this:
public List<Department> getRecords(Date dateFirst, Date dateLast){
Session session= sessionFactory.openSession();
session.beginTransaction();
Query query = session.getNamedQuery("Department.byDate");
query.setDate("first", dateFirst);
query.setDate("last", dateLast);
List<Department> depList = (List<Department>)query.list();
session.getTransaction().commit();
session.close();
return depList;
}
My method of getting that first and last days of the months looks like this:
Calendar first = Calendar.getInstance();
first.set(Calendar.getInstance().get(Calendar.YEAR), Calendar.getInstance().get(Calendar.MONTH), Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
Date dateFirst = first.getTime();
Calendar last = Calendar.getInstance();
first.set(Calendar.getInstance().get(Calendar.YEAR), Calendar.getInstance().get(Calendar.MONTH), Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH));
Date dateLast = last.getTime();
In HQL/JPQL you are working with entities and their properties, thus * character has no meaning.
HQL/JPQL class and property names are case sensitive.
You should write your query the following way:
select d from Department d where d.date >= :first AND d.date <= :last
I want to extract the year part from a row in the database in order to compare it with a value.
Here's my function
public List<Dossier> getAllDossierParAn() {
Date date = new Date();
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
int strI = calendar.get(Calendar.YEAR);
TypedQuery<Dossier> query;
query = em.createQuery("SELECT d FROM DOSSIER d WHERE EXTRACT(YEAR ,d.dateCreation)=2015", Dossier.class);
System.out.println(strI);
return query.getResultList();
}
I get always
An exception occurred while creating a query in EntityManager:
Exception Description: Problem compiling [SELECT d FROM DOSSIER d WHERE EXTRACT(YEAR FROM d.dateCreation)=2015]. [14, 21] The abstract schema type 'DOSSIER' is unknown. [48, 62] The state field path 'd.dateCreation' cannot be resolved to a valid type.
I test it directly in the database and it works
select * from dossier where extract(year from date_creation)=2015
I'm using jpa and ejb and jdeveloper as IDE.
First, the main problem with your query is what the error message say:
The abstract schema type 'DOSSIER' is unknown
Since JPA is mapping your POJOs as entities, their names are case sensitive. Your query should be:
SELECT d FROM Dossier d WHERE ...
Also, regarding the problem you mentioned, the EXTRACT function is only supported by EclipseLink, as far as I know. By the error message, I think this is your JPA implementation, but if it's not, there are two options:
If you're using Hibernate, it has built in functions for retrieving date parts, such as YEAR(date), MONTH(date), DAY(date), HOUR(date), MINUTE(date) and SECOND(date).
For any other JPA implementation, or if you want to keep it JPQL compliant, you can workaround with SUBSTRING: SUBSTRING(d.dateCreation, 1, 4). Note the first position of a string is denoted by 1;
Hope it helps
"Directly in the database" is called SQL.
createQuery takes in JPQL not SQL, and YEAR / EXTRACT are invalid keywords (though YEAR, but not EXTRACT, is supported by some JPA providers). Any decent JPA docs would spell that out.
thank you guys i solved the problem:
first i got the current year than format it to int than to String in order to do the comparaison and substract it here's my code it work fine:
public List<Dossier> getAllDossierParAn() {
Date date = new Date();
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
int strI = calendar.get(Calendar.YEAR);
String strInt =Integer.toString(strI);
String nvlstri= strInt.substring(2, 4);
TypedQuery<Dossier> query;
query = em.createQuery("SELECT d FROM Dossier d WHERE SUBSTRING(d.dateCreation, 7, 2) = :vr", Dossier.class);
query.setParameter("vr",nvlstri);
System.out.println("l anne est " +strI);
System.out.println("la date formaté " +nvlstri);
return query.getResultList();
}
On eclipselink, the way that works for me was something like:
SELECT a.id, EXTRACT(WEEK CURRENT_DATE ) FROM Account a
This works on postgres and sql server at least but should work with other supported databases too.
From javadocs the syntax supported is :
extract_expression ::= EXTRACT(date_part_literal [FROM] scalar_expression)
The FROM seems to cause funny exceptions on sql server.