Get distinct months from database using HQL - java

I have a java.util.Date field in an #Entity and would like to get the distinct months from that column.
Suppose I only had three rows, with 14/07/2010, 24/11/1975 and 03/11/1975 (European date format - day/month/year), I would like to get the following back from Hibernate to go into a dropdown for filtering the data:
07/2010
11/1975
(or corresponding Date objects with the other fields set to zero - to be honest precisely how the data comes back isn't too important as I can work around that).
I'm guessing a database-agnostic approach in HQL isn't possible - any suggestions?

What about :
select distinct month(c.birthday), year(d.birthday) from Cat c

Related

Creating and querying tables with JPA - How to return multiple rows?

I would like to create such tables in MySQL with Hibernate/JPA.
SENSOR: PK_SENSOR_ID, SENSOR_NAME, SENSOR_URL
SENSOR_DATA: FK_SENSOR_ID, DATE, TIME, VALUE
SENSOR_DATA will contain readings from multiple sensors. Then I would like to have a method which use this query:
"SELECT AVG(VALUE), DATE, SENSOR_NAME, FROM SENSOR, SENSOR_DATA WHERE DATE BETWEEN '2019-03-01' AND '2019-03-02' AND SENSOR_ID = FK_SENSOR_ID GROUP BY DATE"
It would return an array of an average values of 'value' per each day (with date and sensor_name).
At this moment I know that I have to create a model for SENSOR with #Entity but what about SENSOR_DATA?
So far, I tried to create a simple model, repository and service with date, time and value and then query it but the problem was that I was able to only get single row for a single day. In this way I would have to create lots of objects for each day separately which doesn't make sense. I assume that it was because of that I used #Entity and added id, but I couldn't figure out a different solution. What I want is to create a single Sensor object and then query through SENSOR_DATA table.
Stack: Spring Boot, Spring Boot Data JPA Starter, Hibernate, MySQL, Lombok,
I really don't think the sql you have will work because of the group by. Correct me if I am wrong.
If you using Hibernate and Spring data jpa. You can do new Object in hql.
Say if the entity that mapped to SENSOR_DATA is sensorDate.
And your sensor object has constructor (double ave, Date date, String sensorName)
Example:
#Query("select new path/to/Sensor(avg, date, sensorName)
from sensorDate sd
where sd.date <:fromDate and sd.date > :toDate and sd=:fksd)")
public list<Sensor> findSensor(#Param("fromDate")Date fromDate, #Param("toDate")Date toDate, #Param("fksd")SensorDate fksd);
Let me explain:
when new keyword, hibernate will convert the output of the sql and mapped to sensor object and into list. Also since you are using hibernate, it is better to use ORM, when compare id, you can just compare the object, internally hibernate will convert hql to sql and compare their pk.
I am making a lot of assumption, but you get the idea. As long as you can get the value you want, you can do a new and pass them into the pojos you have.
As I couldn't figure out how to do it with JPA, I just used Spring JDBC and it works great. I based on a example implementation from this link:
Link

CLOB and CriteriaQuery

I have an entity that has a CLOB attribute:
public class EntityS {
...
#Lob
private String description;
}
To retrieve certain EntityS from the DB we use a CriteriaQuery where we need the results to be unique, so we do:
query.where(builder.and(predicates.toArray(new Predicate[predicates.size()]))).distinct(true).orderBy(builder.asc(root.<Long> get(EntityS_.id)));
If we do that we get the following error:
ORA-00932: inconsistent datatypes: expected - got CLOB
I know that's because you cannot use distinct when selecting a CLOB. But we need the CLOB. Is there a workaround for this using CriteriaQuery with Predicates and so on?
We are using an ugly workaround getting rid of the .unique(true) and then filtering the results, but that's crap. We are using it only to be able to keep on developing the app, but we need a better solution and I don't seem to find one...
In case you are using Hibernate as persistence provider, you can specify the following query hint:
query.setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false);
This way, "distinct" is not passed through to the SQL command, but Hibernate will take care of returning only distinct values.
See here for more information: https://thoughts-on-java.org/hibernate-tips-apply-distinct-to-jpql-but-not-sql-query/
Thinking outside the box - I have no idea if this will work, but perhaps it is worth a shot. (I tested it and it seems to work, but I created a table with just one column, CLOB data type, and two rows, both with the value to_clob('abcd') - of course it should work on that setup.)
To de-duplicate, compute a hash of each clob, and instruct Oracle to compute a row number partitioned by the hash value and ordered by nothing (null). Then select just the rows where the row number is 1. Something like below (t is the table I created, with one CLOB column called c).
I expect that execution time should be reasonably good. The biggest concern, of course, is collisions. How important is it that you not miss ANY of the CLOBs, and how many rows do you have in the base table in the first place? Is something like "one chance in a billion" of having a collision acceptable?
select c
from (
select c, row_number() over (partition by dbms_crypto.hash(c, 3) order by null) as rn
from t
)
where rn = 1;
Note - the user (your application, in your case) must have EXECUTE privilege on SYS.DBMS_CRYPTO. A DBA can grant it if needed.

Mapping partial column values using Toplink

Suppose I have a list of IDs as follows:
EmployeeID
-------
ABCD
AECD
ABDF
ACDF
ACDE
I have a need to read the distinct values from a list of codes, while selecting only the first two characters of the column.
In other words, its similar to using the following query:
SELECT DISTINCT LEFT (EmployeeID,2) FROM TABLE1
My question is how do I map such a field in TOPLINK.
Note:I have created a class for the EmployeeID, but dont have an idea of mapping a partial field.
Ok... After looking at many workarounds, I seem to have a more suited solution.
I created an object for this particular scenario (the POJO has only the field for the holding the 2 Char ID, and its getter and setter methods).
During the mapping, I mapped the above field to the DB column in question (EmployeeID in the table described above).
Now I selected "Custom Queries" for the above object and entered the following query for "Read all" tab.
SELECT DISTINCT LEFT (EmployeeID,2) AS EmploeeID FROM TABLE1
All the read all operations on the object will now return the list of distinct first 2 characters of IDs.
Welcome anyone's opinion on this.

sql java queries

I have a java object 'star' that consists of two columns, string name (the name of the star) and string List fans (the list of fans of this star). I'd like to persist this class using JPA1 or hibernate. I've done so using the annotation #collectionOfElements on the list. It works fine, and creates two tables.
Now I'd like to get all stars whose fans are 'alice' or 'bob' or 'charlie'. How can I do that in the easiest way (only one query rather than 3, and without using 'OR' statements if possible), using jpa queries (hibernate if it's a must), and without retrieving the whole list of fans ?
Thanks
The following query should help you:
select s.* from star s where s.fans.name in ('alice', 'bob', 'charlie')

Query by age in hql

I have a class User with one field called birthDate which is a java.sql.Date.
How do I do a hql query that will retrieve all Users that are between min and max years old?
(My real scenario is slightly more complex than that but that's where I am stuck right now).
UPDATE
It must be an hql expression so I can put the age expression in a computed property.
Calculate the birth dates corresponding to the min and max ages. Then use the below HQL.
Select u from User u where u.birthDate between :minDate and :maxDate
Setup the the minDate and maxDate to the values you computed before executing the query.
It depends on the database. Most have some way of handling date arithmetic. MySQL has a datediff function that will return a number of days so you could divide that by 365 and get pretty close. The MySQL dialect already has datediff as a registered function. For other databases you may need to use different functions and possibly register them in a custom dialect. But you may be off by a little unless you take leap years into account which is tricky in an HQL expression. Using dates is easier because you can keep the month and day constant, change the year, and then use < or > in HQL.

Categories