I would like to get all distinct years from a MySQL date field with the Hibernate Criteria API. This is the query that I want to translate to criteria:
sess.createQuery("SELECT DISTINCT year(o.date) FROM Observation");
I've tried :
Criteria crit = sess.createCriteria(Observation.class)
.setProjection(Projections.distinct(Projections.property("year(date)")));
But it returns an error
ERROR - could not resolve property: year(date) of: ca.ogsl.biodiversity.hibernate.Observation
Does any body knows if it's possible and how?
Thanks a lot!!!
Keven
Try using an sql projection, so you can use any SQL expression:
criteria.setProjection(Projections.sqlProjection( "yeard(DATE_COLUMN_NAME) as year", new String[] {"year"}, new Type[] {StandardBasicTypes.INTEGER} ));
Use the DISTINCT keyword to query for distinct years, rather than getting all years and trying to filter them in Java code.
SELECT DISTINCT year(o.date) FROM Observation;
Related
I use spring boot, and I want to add 1 year to a specific column in mysql database
String queryRecherche = "UPDATE myTable t SET t.dateDebut = DATE_ADD(t.dateDebut, INTERVAL 1 YEAR) WHERE.id = 3 ";
Query query = em.createQuery(queryRecherche);;
query.executeUpdate();
But I get the folowing error :
org.hibernate.query.sqm.ParsingException: line 1:66 no viable alternative at input 'DATE_ADD(t.dateDebut,INTERVAL1'
Have you please any suggestions to do this.
You're using Hibernate 6 (I can tell by the error message), so the correct HQL syntax to use is:
UPDATE MyEntity t SET t.dateDebut = t.dateDebut + 1 year WHERE t.id = 3
You had three errors in your query:
You referred to the name of a table instead of the name of an entity class in the UPDATE clause.
You used the unportable MySQL DATE_ADD function instead of the portable HQL date/time arithmetic described here.
The syntax of your WHERE clause was garbled.
Perhaps you meant for this to be a native SQL query, in which case you called the wrong method of Session. But there's no need to use native SQL for the above query. As you can see, HQL is perfectly capable of expressing that query.
You can use SQL directly, via createNativeQuery, or register a new function as shown in this example to call it from HQL
I have a query like below:
select * from Products p where ? between p.effctDate and p.expDate
Can I translate the above query to a spring data jpa query method? Like for example:
findByProductId(productId)
or I only have to use #Query or a Named query to handle such types of queries. I tried searching here first before asking the question as well as spring data site but did not find any solution. any help is appreciated.
You could use the following query:
Date date = //Input date
List<Product> = findByEffctDateAfterAndExpDateBefore(date, date);
Note that you have to enter date twice to match both 'where' clauses. This is under the assumption you are using Date objects, not literal Strings.
See JPA Repositories Table 2.3 for more info.
You can try to use something like below :
List findAllByDateApprovedBetween(String dateApprovedFrom, String dateApprovedTo);
It translates to :
Hibernate: select applicatio0_.id as id1_1_, applicatio0_.date_approved as date_app4_1_ from application applicatio0_ where (applicatio0_.date_approved between ? and ?)
You can try something like this trick:
select
p
from
Product p
where
(?1 = 'field1' and p.field1 between p.effctDate and p.expDate)
or (?1 = 'field2' and p.field2 between p.effctDate and p.expDate)
or (?1 = 'field3' and p.field3 between p.effctDate and p.expDate)
or (?1 = 'field4' and p.field4 between p.effctDate and p.expDate)
...
But this is not the best approach IMO...
To build dynamic queries you can use thees ones:
Specifications
Query by Example
Querydsl Extension
I have a question (sorry about my English, I'm learning)!
I searched everywhere for how to use the command sum(column) with HQL hibernate language, but I can't find anything!
I can do it with SQL language. Example:
SELECT sum(Column) FROM tablethatIwantthevalues;
but not with HQL Hibernate!
You can use same query as SQL, try below solution :
Session s = OptimazPoolM.getSessionFactory().openSession();
String sumHql = "SELECT SUM(salary) FROM employees WHERE idemployee = 31";
Query sumQuery = s.createQuery(sumHql);
System.out.println(sumQuery.list().get(0));
You can use aggregation functions in HQL as well as in SQL, take a look at the Hibernate Query Language Manual: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html#queryhql-aggregation
I am writing a query to find dates and their counts for that particular date from my entity table, and running into an issue with the groupBy statement.
Here is my criteria API calls:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root<HtEntity> from = criteriaQuery.from(entityClassType);
Expression<String> log_date = criteriaBuilder.function("TO_CHAR",
String.class, from.get(Constants.PARAM_DATE), criteriaBuilder.literal("yyyy-MM-dd")
);
//create the select statement
criteriaQuery.select(
criteriaBuilder.tuple(
log_date.alias("log_date"),
criteriaBuilder.count(from)));
criteriaQuery.groupBy(log_date); //ISSUE HERE!!!
TypedQuery<Tuple> query = em.createQuery(criteriaQuery);
List<Tuple> results = query.getResultList();
Without trying to cast the date column with to_char and using just the date column it works, but obviously is not aggregated as I want to. I want just the date in yyyy-MM-dd and not the entire timestamp, and I can only see doing this by using groupBy which causes an error
"org.hibernate.exception.SQLGrammarException: could not extract
ResultSet"
And there is the query string that is build found from my debugger:
select function('TO_CHAR', generatedAlias0.date, :param0), count(generatedAlias0) from LogMessageEntity as generatedAlias0 group by function('TO_CHAR', generatedAlias0.date, :param1)
Please let me know what I am doing wrong. The corresponding Postgres SQL query should be working for this, as I can test it and see that it would work.
CriteriaApi has a good way of providing me with a headache, but I did end up finding a solution to this a while back, providing the answer for future curious folks:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
Root<MyEntity> from = criteriaQuery.from(classType);
criteriaQuery.multiselect(
from.get("date").as(java.sql.Date.class),
criteriaBuilder.count(from)
);
/*Add order by and group by clause*/
criteriaQuery.orderBy(criteriaBuilder.desc(from.get("date").as(java.sql.Date.class)));
criteriaQuery.groupBy(from.get("date").as(java.sql.Date.class));
TypedQuery<Object[]> query = em.createQuery(criteriaQuery);
List<Object[]> results = query.getResultList();
You will notice that I am casting the column projecting in my multi-select statement, and my groupBy as a java.sql.Date type. CriteriaApi has a strict type-safe format such that you cannot mix types for the groupBy and the select statement if you are aggregating on that specific column. My issue was that I was selecting on the date column with a function call, and also trying to apply that to the groupBy.
While the generated query statement works via command line, it does not work for the CriteriaApi. The reason it cannot generate a ResultSet is due to it assuming the projection and aggregation in the groupBy are not the same type (I think) and therefore, if you need to use a function on a column in your select statement and also aggregate on that column you need to either think of a way you can avoid using the function (which is what I did), or generate a native query with the Hibernate EntityManager object you have.
It is unfortunate, but I believe CriteriaApi has a number of limitations with this being one of them. It should probably be submit to their team as a bug, but I'm not sure where to do this.
Old question, but the issue is still relevant. I've tried your solution, but it didn't work for me. What did work is the trunc function, instead of the to_char:
Path<FeedbackType> feedbackTypePath = itemRoot.get("feedbackType");
final Expression date = criteriaBuilder.function("trunc", java.sql.Date.class, votesJoin.get("creationDate"));
selects.add(feedbackTypePath);
selects.add(date);
selects.add(criteriaBuilder.count(itemRoot.get("id")));
criteriaQuery.multiselect(selects);
criteriaQuery.where(criteriaBuilder.equal(votesJoin.get("creationDate"), oldestVoteSubquery));
criteriaQuery.groupBy(feedbackTypePath, date);
It looks like the criteriabuilder does not like the literal in the groupBy.
I need to use the LIKE operator into an JPA query. I need to use it for types other then String but the JPA criteria API allows me to add only String parameters. I tried using the .as(String.class) but something fails and also tried calling the CAST function from the underlying Oracle that again fails for unknown reasons to me.
I tried writing the query also in JPQL and it works as expected. This is the query:
SELECT p from CustomerOrder p where p.id like '%62%'
UPDATE:
The query must be built in a generic fashion as it is for filtering, so it needs to be created at runtime. On the query that is already created I tried to add the LIKE clause like this:
query.where(builder.like(selectAttributePath.as(String.class), "%"+filterValue.toString().toLowerCase()+"%"));
But this crashes with this exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found '(' near line 1, column 156 [select distinct generatedAlias0.id from de.brueckner.mms.proddetailschedact.data.CustomerOrder as generatedAlias0 where cast(generatedAlias0.id as varchar2(255 char)) like :param0]
I executed the same query directly to Oracle using SQLDeveloper, so it should be sound from this point of view. So the problem is the Hibernate is the issue. Any suggestions on how to fix it?
How can I write this query using JPA Criteria?
I fixed the problem by invoking the 'TO_CHAR' function from the underlying Oracle DB and using the LIKE operator like for normal String's.
query.where(builder.like(selectAttributePath.as(String.class), "%" +filterValue.toString().toLowerCase() + "%")
You can try the below code, it might require modifications.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CustomerOrder> cq = cb.createQuery(CustomerOrder.class);
Root<CustomerOrder> order = cq.from(CustomerOrder.class);
cq.where(cb.like(Long.valueOf(order.get(CustomerOrder_.id)).toString(), "%62%"));
TypedQuery<CustomerOrder> q = em.createQuery(cq);
List<CustomerOrder> results = q.getResultList();