Comparing two columns in Hibernate Criteria - java

I have a table in Postgre Database. The table has 2 timestamp format columns. I need those rows where one column timestamp is not equals the second column timestamp.
For the below query I need the Hibernate criteria restrictions.
select * from A where column1<>column2

Did you try something like that?
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> cQuery = builder.createQuery(Foo.class);
Root<Foo> from = cQuery.from(Foo.class);
CriteriaQuery<Foo> select = cQuery.select(from);
select.where(builder.notEqual(from.get("col1"), from.get("col2")));
List<Foo> result = entityManager.createQuery(select).getResultList();

Given your comment here, you'll have to do a full table scan, which will create troubles with a bigger table. You will likely need to change your approach altogether, and introduce a field which says something like "IsUpdated". Or, when creating that record, UpdatedTime should be set to null, indicating it hasn't been updated yet. Then, you can do a query like "give all records where UpdatedTime is not null".

Related

Java Spring JPA: How to find the sum of only non null values in a column?

I currently have a query like this:
SELECT DISTINCT t.column1, SUM(t2.column2 IS NOT NULL)
FROM table t
LEFT OUTER JOIN table t2 on table.id = t2.id
GROUP BY column1, column2;
I am trying to implement the query using Spring JPA CriteriaBuilder. I see the CriteriaBuilder.sum() method, but I don't see a way to apply the IS NOT NULL part to the selection. Column2's data type is string.
Sample of my code
criteriaBuilder.multiselect(root.get("column1"), cb.sum(root.get("column2")));
Only in MySQL would such a query run, due MySQL’s relaxed syntax rules.
In particular, in mysql sum(column2 is not null) is a count, not a sum. The expression column2 is not null is boolean and in mysql false is 0 and true is 1, so summing this expression is a mysql hack to count the number of times column2 is not null.
To convert it to standard sql:
select
t.column1,
count(t2.column2)
from table t
left join table t2 on t.id = t2.id
group by t.column1
This works because count() (and all aggregate functions) ignore nulls.
This version also corrects the errant column in the group by clause - in any other database, your query would have produced a “grouping by aggregate expression” error.
This query will produce the same result in MySQL as your current query.
I was able to find a solution to my problem. Thanks to #bohemian for helping me write a correct sum expression.
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Model1> cq = cb.createQuery(Model1.class);
final Root<Model1> root = cq.from(Model1.class);
final Join<Model1, Model1> selfJoin =
root.join("tableJoinColumn", JoinType.LEFT);
selfJoin.on(...);
cq.multiselect(root.get("column1"), cb.sum(cb.selectCase()
.when(cb.isNull(selfJoin.get("column2")), 0).otherwise(1).as(Long.class)));
...
The self join required me to create an additional property on my model.
Model1.java
/**
* Property for LEFT INNER JOIN.
*/
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="id")
private Model1 tableJoinColumn;
How to use JPA CriteriaBuilder selectCase() so that it can have Predicate as result?
Self join in criteria query

Specfiy columns which should be considered for distinct calculation

I'm using javax.persistence.criteria.CriteriaBuilder and javax.persistence.criteria.CriteriaQuery to select some entities.
I now want to select only the entities that are unique which should be specified by a certain column.
There is the method javax.persistence.criteria.CriteriaQuery#distinct which only returns unique entities.
I would rather need something like
CriteriaQuery<T> distinct(String... columnNames)
Do you know how I can bake such a distinct in my JPA CriteriaQuery?
It seems to be possible with Hibernate.
The following statement has no sense:
I now want to select only the entities that are unique which should be
specified by a certain column.
The result sets are filtered by 'distinct' if they are 'exactly the same'.
The entities are not the same if only some fields are the same.
You can make distinct clause on resultset in the following manner:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery();
Root<Friend> c = query.from(Friend.class);
query.multiselect(c.get(Friend_.firstName),c.get(Friend_.lastName)).distinct(true);
then you will get unique combination of firstName and lastName from Friend entities.
So for instance... 'Give me all unique combinations from my Friends where the firstName and lastName of the friend is unique.' But it doesn't mean give me unique friends.
distinct takes a boolean as parameter. You can use multiselect to select more than one column like in this example:
CriteriaQuery<Country> q = cb.createQuery();
Root<Country> c = q.from(Country.class);
q.multiselect(c.get("currency"), c.get("countryCode")).distinct(true);

How to get only two column result instead of entire row?

My query like this,
String sql="select p.productName,p.extendedFlag from product p where productId=? and productVersion=?";
SqlQuery sqlQuery=session.createSQLQuery(sql).addEntity(Product.class);
sqlQuery.setParameter(0,"newprofin2");
sqlQuery.setParameter(1,"newprofin2");
List product =sqlQuery.list();//error at this line
Product p=(Product)product.get(0);
please Help me,
and i am using Hibernate 3.
If you want to return the result as an entity you need to use "select * ..." (so hibernate can map all the column annotations) otherwise you have to stick with selecting only scalar values that are not mapped to the entity and need to be processed on a column basis.
Examples:
http://www.tutorialspoint.com/hibernate/hibernate_native_sql.htm

Need help regarding HIbernate count query

We have a use case to count no. of rows returned by actual query. I am not getting how can I get it using criteria in hibernate.
For example suppose I want to run query
select sum(TOTAL_EARNINGS) from table where column1 = 'value1' group by column2);
Along with this query result I also want to get total rows return by above query(above query may have rownum limit also but for total rows I have to ignore rownum limit).
select count(*) from (select sum(TOTAL_EARNINGS) from table
where column1 = 'value1' group by column2);
Is there any easy way of getting this data. I am fine with running separate query to get count data but I am not getting how can I write this in hibernate using criteria. I can't even see any option in SubQueries which I can use
In general with criteria you can use projections.
You can do so, if you have an entity "Your" mapped by Hibernate:
Edited:
Accordingly to your comment, you need two results, a total count and a group by results.
//the group by results...
List result1 = session.createCriteria("Your.class").setProjection(Projections.projectionList()
.add(Projections.groupProperty("column2"))
.add(Projections.sum("totalErnings"))
).list();
//the total count result
return (Integer) session.createCriteria("Your.class").add(Restrictions.eq("column1", val)).setProjection(Projections.rowCount()).uniqueResult();

Hibernate Criteria -- return records where column is distinct

Sample database table:
ID = 1, msgFrom = 'Hello', foobar = 'meh'
ID = 2, msgFrom = 'Goodbye', foobar = 'comments'
ID = 3, msgFrom = 'Hello', foobar = 'response'
Sample desired output (generated by hibernate query):
ID = 1, msgFrom = 'Hello', foobar = 'meh'
ID = 2, msgFrom = 'Goodbye', foobar = 'comments'
In the above example, the third record would be excluded from the results since the msgFrom column is the same. Let's say the Java/Hibernate class is called Message. I would like the results to be returned as a list of Message objects (or Objects that can be cast to Message, anyway). I want to use the Criteria API if possible. I saw this example on SO and it seems similar but I cannot implement it correctly as of yet.
select e from Message e
where e.msgFrom IN (select distinct m.msgFrom
from Message m
WHERE m.msgTo = ?
AND m.msgCheck = 0");
The reason I am doing this is to have the filtering of distinct records done on the database, so I am not interested in answers where I have to filter anything on the application server.
edit: Article showing basically what I want to do. http://oscarvalles.wordpress.com/2008/01/28/sql-distinct-on-one-column-only/
Please try this and let me know
DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("messageFrom"));
properties.add(Projections.min("id"),"id");
msgFromCriteria.setProjection(properties);
Criteria criteria = s.createCriteria(Message.class);
criteria.add(Subqueries.propertiesIn(new String[]{"messageFrom","id"},
msgFromCriteria));
List<Message> list = criteria.list();
for(Message message:list){
System.out.println(message.getId()
+"-------"
+message.getMessageFrom()
+"-----"
+message.getFoobar());
}
The difficulty with this query is not so much with Hibernate, per se, but with the relational model in general. In the example, you say you expect rows 1 and 2, but why wouldn't you just as easily expect rows 2 and 3? It would be an arbitrary decision whether to return row 1 or row 3 since they both have the same value in the msgFrom field. Databases won't make arbitrary decisions like this. That's why distinct must be applied to the entire list of select columns, not a subset. There are database-specific ways of grabbing the first matching rows. For example, have a look at
SELECT DISTINCT on one column
Sometimes there will be a date column that you can use to decide which of the matching rows to return, but again the queries get somewhat complex:
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
Fetch the row which has the Max value for a column
If you don't care about any of the other columns, you can just use a simple distinct, combined with Hibernate's constructor syntax (not tested):
select new Message(msgFrom) from (select distinct msgFrom from Message)
but you have to accept throwing away all the other columns.
In the end, I often end up just doing this in code as a post query filter. Another option is to create a another table, say CurrentMessage, that includes msgFrom as part of the key. There will be more work in keeping this table up to date (you need to update a row everytime you add a row to the Message table) but querying will be much easier.
DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
msgFromCriteria.setProjection(Projections.distinct(Projections.property("msgFrom")));
....
Criteria criteria = getSession().createCriteria(Message.class);
criteria.add(Subqueries.propertyIn("msgFrom", msgFromCriteria));
criteria.list();

Categories