Need help regarding HIbernate count query - java

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();

Related

Spring Data JPA - count number or results of query

I want to get the number of results of a query in Spring Data Jpa, using a non-native #Query method. It consists of a basic group by plus a having clause.
My plain query looks like this (analogous example):
select count(*) from (
select 1 from table t
where t.field_a = 1
group by t.id
having count(*) = 2) a;
Since Hibernate 5 does not allow subqueries in the form clause, I have to find a workaround for that. The only one I found is very inefficient as per the query plan:
select count(*) from table t
where t.field_a = 1 and
2 = (select count(*) from table temp where temp.id = t.id);
Is there a way to write a Spring Data JPA query that's as efficient as the first one? I can think of no solution rather than selecting the inner query and taking its size() in java, but that can produce issues due to a ton of redundant data passing through the network.
There is no easy solution to count the results of a subquery in JPA but the a workaround is proposed here https://arjan-tijms.omnifaces.org/2012/06/counting-rows-returned-from-jpa-query.html.
The principle is to build a native query based on the initial Jpa subselect query.
This does the job if you accept to count the elements in java !
Query q = em.createQuery(
"select 1 from table t where field_a = 1 " +
"group by t.id having count(*) = 2");
int count = q.getResultList().size();
(performances depending on the number of lines returned, but the projection is very light : 1)

Java sql - delete half rows in DB table

I want to delete a bunch of rows from a DB file that I have in a folder. Connecting and counting the amount of rows in the db file works but when I try to delete a specific amount of rows I get stuck.
Input:
sql = "SELECT COUNT(*) AS id FROM wifi_probe_requests";
...
sql = "DELETE FROM wifi_probe_requests LIMIT " + rowcount/2;
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();
Output:
54943
[SQLITE_ERROR] SQL error or missing database (near "LIMIT": syntax error)
Not using a limit works fine and I can delete the entire db table but what I want is to delete half the db rows as seen by the rowcount/2 I made.
UPDATE:
So far I have solved the problem by finding the id which is located at the n-rows/2 and then getting the value of it (ex. 264352). Then using that number to indicate what id rows are going to be deleted (ex. id.value < 264352).
sql = "SELECT COUNT(*) AS id FROM wifi_probe_requests";
int rowcount = COUNT(*);
sql = "DELETE FROM wifi_probe_requests WHERE id < (SELECT id FROM wifi_probe_requests ORDER BY id ASC LIMIT "+ rowcount/2 + ",1)";
rowcount = 50000
Delete valueof.id < valueof.id.50000/2
So all values of id below the value of an id at position 25000 will be deleted.
You can't. Some databases don't allow LIMIT in UPDATE or DELETE queries.
It seems that with SQLite it's possible to work around that, by compiling your own version, but if you're not willing to do that, you need to rewrite your query in a different way. For example if you have an autoincrement id in the table, you can calculate the "middle" id and use WHERE id < [middle id] as an alternative to LIMIT.
As stated by #Kayaman this is not possible using SQLITE.
You can bypass this with a query such as;
DELETE FROM wifi_probe_requests WHERE id IN (SELECT id FROM wifi_probe_requests LIMIT 10)
One more thing; I don't think (rowcount/2) will work when you have an uneven amount of rows as it will not result in an integer. I think you will have to round it down/up.
How fancy do you want to make this? A simple solution would be something like:
SELECT COUNT(*) FROM mytable;
"SELECT id FROM mytable order by id LIMIT 1 OFFSET " + round(rowcount/2)
DELETE FROM mytable WHERE id < ?
If you go that route, you should be able to delete the first half of your rows by keyspace. If you just want just about half your rows deleted (and don't really care how many) you could probably find a way to use RANDOM() to do this. Probably like (WARNING TOTALLY UNTESTED):
DELETE FROM mytable WHERE random() < 0.5;

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

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();

Problem with processing count column with Hibernate

I want to process the count column in my action how to do with help of hiberante.in my application every class is mapped to every table here I'm using billing table. In billing table details and other columns are there.
If i pass the query into execute sql query method it getting all the details, but it returns the count column as that corresponding dao class. How to process that column. Here is my query.
select u,b,b,count(b.details) from com.cod.model.Billing b,com.cod.model.User u where b.accountId=u.id and b.details not like '%Monthly Package With Usage Value Rs:0.0%' and b.details not like '%A/C Opened:%' and b.details not like '%Voucher Recharged%' and b.details not like '%default0%' group by u.username,b.details
Here it's getting user and billing table values but count column also comes as billing table object.
Don't make the results list type safe or hibernate will grab everything he can and push it in an instance of that object. When you make your results list not type safe hibernate will just return an List over which you can iterate and retrieve the fields you need.
List.get(0)[3] should result in you having your count.
String hql = "...";
Query query = session.createQuery(hql);
//List< com.cod.model.Billing> results = query.list();
List results = query.list();

Categories