How to write criteria eqivalent of sql having count [duplicate] - java

I need to create a query and I need COUNT(*) and HAVING COUNT(*) = x.
I'm using a work around that uses the CustomProjection class, that I downloaded somewhere.
This is the SQL that I try to achieve:
select count(*) as y0_, this_.ensayo_id as y1_ from Repeticiones this_
inner join Lineas linea1_ on this_.linea_id=linea1_.id
where this_.pesoKGHA>0.0 and this_.nroRepeticion=1 and linea1_.id in (18,24)
group by this_.ensayo_id
having count(*) = 2
This is the code, where I use the Projection Hibernate class:
critRepeticion.setProjection(Projections.projectionList()
.add( Projections.groupProperty("ensayo") )
.add( CustomProjections.groupByHaving("ensayo_id",Hibernate.LONG,"COUNT(ensayo_id) = "+String.valueOf(lineas.size()))
.add( Projections.rowCount() )
);
The error is:
!STACK 0
java.lang.NullPointerException
at org.hibernate.criterion.ProjectionList.toSqlString(ProjectionList.java:50)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getSelect(CriteriaQueryTranslator.java:310)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:71)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:67)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1550)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at ar.com.cse.cseagro.controller.RepeticionController.buscarEnsayo(RepeticionController.java:101)
If I comment the line with CustomProjections class, the query work, but I don't get the HAVING COUNT(*) filter in the SQL ...
Basically the query try to retrieve, in a master - detail schema, all the master records where a list of details are simultaneously present, like if you want tho know "which invoices have both products, A and B".
That why if I got 3 items in the IN clause, I need to use HAVING COUNT = 3 clause.
Any idea or suggestion?
Best regards,

I figured out the problem. I replace CusotmProjections class, with:
.add( Projections.sqlGroupProjection("ensayo_id", groupBy , alias, types));
where groupBy, alias and types are:
String groupBy = "ensayo_id" + " having " + "count(*) = " + String.valueOf(lineas.size());
String[] alias = new String[1];
Alias[0] = "ensayo_id";
Type[] types = new Type[1];
types[0] = Hibernate.INTEGER;
and the magic is on groupby String. –

If someone needs to do it in grails it would be like:
projections {
groupProperty("id")
sqlGroupProjection(...)
rowCount()
}
Where sqlGroupProjection is available since 2.2.0
/**
* Adds a sql projection to the criteria
*
* #param sql SQL projecting
* #param groupBy group by clause
* #param columnAliases List of column aliases for the projected values
* #param types List of types for the projected values
*/
protected void sqlGroupProjection(String sql, String groupBy, List<String> columnAliases, List<Type> types) {
projectionList.add(Projections.sqlGroupProjection(sql, groupBy, columnAliases.toArray(new String[columnAliases.size()]), types.toArray(new Type[types.size()])));
}
http://grepcode.com/file/repo1.maven.org/maven2/org.grails/grails-hibernate/2.2.0/grails/orm/HibernateCriteriaBuilder.java/#267

Here is my sample, it works fine, maybe useful :
My sql query :
select COLUMN1, sum(COLUMN2) from MY_TABLE group by
COLUMN1 having sum(COLUMN2) > 1000;
And Criteria would be :
Criteria criteria = getCurrentSession().createCriteria(MyTable.Class);
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("column1"), "column1");
projectionList.add(Projections.sqlGroupProjection("sum(column2) sumColumn2 ", "COLUMN1 having sum(COLUMN2) > 1000" , new String[]{"sumColumn2"}, new org.hibernate.type.Type[]{StandardBasicTypes.STRING}));
criteria.setProjection(projectionList);
criteria.List();

criteria.add(Restrictions.sqlRestriction("1=1 having count(*) = 2"));

Related

JQPL select inside select

just switched to spring boot from .NET Core, in .NET core we can easily nest a select inside a select like this:
var result = from c in context.Cars
join br in context.Brands
on c.BrandId equals br.Id
join col in context.Colors
on c.ColorId equals col.Id
select new CarDetailDto
{
Id = c.Id,
BrandName = br.Name,
CarName = c.Name,
ColorName = col.Name,
DailyPrice = c.DailyPrice,
ModelYear = c.ModelYear,
CarImages = (from cimg in context.CarImages
where cimg.CarId == c.Id
select new CarImage
{
Id = cimg.Id,
ImagePath = cimg.ImagePath,
CarId = c.Id,
Date = cimg.Date
}).ToList()
};
I want to do that in JPQL as well but didnt manage to solve
#Query( select column1, column2, column3 from tablename1 where coluname=(select columname from tablename2 where columnname=abcd) )
Your JPQL query should look like above.
Whatever subquery you write with condition.
If your query is fetching 3 column you need to create a DTO with same column name.
If your query is fetching list of rows then your actual jpql will look like this.
#Query( select column1, column2, column3 from tablename1 where coluname=
(select columname from tablename2 where columnname=abcd) )
List<ResultDTO> findAllResultList(Parameter value);
Above it is mapping the result to list of DTO objects to result rows.
If your query is fetching single row then your actual jpql will look like this.
#Query( select column1, column2, column3 from tablename1 where coluname=
(select columname from tablename2 where columnname=abcd) )
ResultDTO findResult(Parameter value);
The single result is mapped to one DTO object.
Make sure your result column name and DTO column name matches
Using the JPA repository call the names of the method which you used for the particular query.

JPA limit subquery result (Jhipster)

I need to put
order by tabB.id desc
limit 1
in a subquery because the subquery must return a single value.
Long filter= Long.parseLong(value);
return (root, query, builder) -> {
Subquery<B> subquery = query.subquery(B.class);
Root<B> subqueryRoot = subquery.from(B.class);
Join<B,C> ss = subqueryRoot.join(B_.idC);
subquery.correlate(ss);
subquery.select(subqueryRoot.get(B_.ID_C));
subquery.where(
builder.equal(subqueryRoot.get(B_.idA),root.get(A_.id))
);
subquery.
builder.max(subqueryRoot.get(B_.id)); //first try
builder.desc(subqueryRoot.get(B_.id)); //another try
return builder.equal(subquery, filter);
};
adding "first try" and/or "another try" nothing changes in the query created, they are simply ignored and executing it I reach:
org.postgresql.util.PSQLException: ERROR: more than one row returned by a subquery used as an expression
Is there a way to take the first element in the subquery so can apply to the where query?
My situation is similar What are the alternatives to using an ORDER BY in a Subquery in the JPA Criteria API?
but I have a equals not over the id:
SELECT q.id_project FROM status q
WHERE q.status_name like 'new'
AND q.id IN (
SELECT TOP 1 sq.id from status sq
WHERE q.id_project = sq.id_project
ORDER BY sq.id DESC )
my situation is:
SELECT A.id_project FROM tabA A
WHERE A.col like 'alpha'
AND 'centauri' = (
SELECT TOP 1 B.colAA from tabB B
WHERE A.id_project = B.id_project
ORDER BY B.id DESC )

How can I implement Select and Count in Hibernate using criteria

I'm new using hibernate, I have query like :
select count(1) from (
SELECT COUNT (1)
FROM USR_BASE
WHERE ST_CD = 1
group by USR_NO)
How can I implement that query in Hibernate using criteria ?
Because, I already implement with method :
public int totalUser(UsrBase usrBase) {
Criteria criteria = createCriteria();
String stCd = usrBase.getStCd();
criteria.setProjection(Projections.projectionList())
.add(Projections.property("usrNo"))
.add(Projections.property(stCd))
.add(Projections.groupProperty("usrNo")));
return((Long)criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
}
the result not same with my query... Please help me.
select count(1) from (
SELECT COUNT (1)
FROM USR_BASE
WHERE ST_CD = 1
group by USR_NO)
I think it will be more easily with
select count(distinct(USR_NO)) from USR_BASE WHERE ST_CD = 1

Java SQL Iterating 2 ResultSet and merging them

let's say i have 2 queries and 2 ResultSet. the first one is members table query, while the second query is for other member datas. now i want to join the first resultset with the second one. for example it looks like this
ResultSet rsMember = psMembers.executeQuery();
ResultSet rsCustomValues = psCustomValues.executeQuery();
// object for mapping query results
MembersMapper memberMapper = new MembersMapper();
while (rsMember.next()) {
memberMapper.setId(rsMember.getString("id"));
memberMapper.setName(rsMember.getString("name"));
memberMapper.setUsername(rsMember.getString("username"));
memberMapper.setGroup(rsMember.getString("group_id"));
List strCustomValues = new ArrayList<>();
while(rsCustomValues.next()){
// map the custom values
Map<String, Object> mapTemp = new HashMap<String, Object>();
mapTemp.put(FIELD_ID, rsCustomValues.getString("custom_field_id"));
mapTemp.put(INTERNAL_NAME,
rsCustomValues.getString("custom_field_internalname"));
mapTemp.put(NAME,rsCustomValues.getString("custom_field_name"));
strCustomValues.add(mapTemp);
}
memberMapper.setCustomvalues(strCustomValues);
}
the problem is the second (inner while) query. what connects data between first and second resultset is member id, which is primary key in first table (first query) and foreign key in second query. so the second query will have member id in random order.
so how can i order the second query without having to put 'order by member_id' in the second query? i will have to avoid 'order by member_id' because it will take time to process.
Edit: here's the scripts
First script
select
mbr.*, usr.username, grp.name as groupname, grp.status
from members mbr
join users usr on mbr.id = usr.id
join groups grp on mbr.group_id = grp.id
where mbr.id > #id#
order by id asc
limit #limit#
Second script
select
cfv.member_id as 'member_id', cf.id as 'custom_field_id',
cf.internal_name as 'custom_field_internalname',
cf.name as 'custom_field_name', cfv.string_value as 'cfv_stringvalue',
cfv.possible_value_id as 'cf_possiblevalueid', cfvp.value as 'cfvpvalue'
from custom_field_values cfv
join custom_fields cf on cf.id = cfv.field_id
left join custom_field_possible_values cfvp on cfv.possible_value_id = cfvp.id
where exists(
select * from (select id from members where id > #id#
limit #limit#
) result where result.id = cfv.member_id)
and cf.subclass = #subclass#
order by cfv.member_id asc
It is better to fetch the second result set to an object representation and sort it out.
See a similar question here How can I sort ResultSet in java?

Inner join query on Hibernate - SQL queries do not currently support iteration

I'm new to hibernate and I've this SQL query which works perfectly
SELECT count(*) as posti_disponibili from occupazione t inner join
(select id_posto_park, max(date_time) as MaxDate from occupazione
group by id_posto_park) tm on t.id_posto_park = tm.id_posto_park and
t.date_time = tm.Maxdate and t.isOccupied = 0
which gives me all the last items with isOccupied = 0
I was porting it into Hibernate, I've tried to use
result = ( (Integer) session.createSQLQuery(query).iterate().next() ).intValue()
to return posti_disponibili but i got this exception
java.lang.UnsupportedOperationException: SQL queries do not currently support iteration
How can i solve this? I cannot find the equivalent HQL query
Thank you
I would suggest you to use
Query#uniqueResult()
which will give you single result.
select count(*) .....
will always return you a single result.
Hibernate support it's own iterator-like scroll:
String sqlQuery = "select a, b, c from someTable";
ScrollableResults scroll = getSession().createSQLQuery(sqlQuery).scroll(ScrollMode.FORWARD_ONLY);
while (scroll.next()) {
Object[] row = scroll.get();
//process row columns
}
scroll.close();

Categories

Resources