Java Hibernate a conditional Criterion based on nullability of property is possible? - java

I have a simple query like this.
select id,status,c01,c02,c03 from mytable
where
criterion1
and criterion2
and criterion3
I need to add another filter like this
//In Java
if(mytable.status=1){
criteria.add(Restrictions.eq("anotherFilter",anotherFilterValue));
}
But the status value comes in the query i mean i can filter in memory but i would like to be able to filter in the DB directly
Like the ordering using case can i use some approach to make it?
Like
select id,status,c01,c02,c03 from mytable
where
criterion1 = ?
and criterion2 = ?
and criterion3 = ?
and
case status is null
? anotherFilter = :valueToFilter
: 1=1//IS NOT NULL NOTHING TO DO..

This can help you.
select id,status,c01,c02,c03 from mytable
where
criterion1 = ?
and criterion2 = ?
and criterion3 = ?
and
((status is null and anotherFilter = :valueToFilter)
or (status is not null))
For criterion api
//In Java
criteria.add(
Restrictions.or(
Restrictions.isNotNull("status"),
Restrictions.and(
Restrictions.eq("anotherFilter",anotherFilterValue),
Restrictions.isNull("status")
)
)
);

Related

Incorrect syntax near ')'. SQL query is wrong while running on both DBeaver and on java mapper files?

DECLARE #source as NVARCHAR(MAX) = (SELECT md.[source] FROM sports_service.meet.meet_detail md WHERE md.meet_id = #{meetId})
WHERE reg.is_waitlist = 0 AND reg.cancelled_dt IS NULL
AND NOT EXISTS (
SELECT 1 FROM sports_service.meet.meet_invitations i
WHERE i.meet_id = pmm.meet_id AND i.sports_person_id = reg.sports_person_id)
IF #source != 'MANUAL'
AND EXISTS (
SELECT 1
FROM sports_service.meet.session session
INNER JOIN sports_service.meet.event event ON event.session_id = session.id
WHERE pmm.meet_id = session.meet_id
AND sports_service.dbo.fnGetMeetAge(p.birth_dt, detail.age_up_date, detail.id_format) <![CDATA[>=]]> event.low_age
AND sports_service.dbo.fnGetMeetAge(p.birth_dt, detail.age_up_date, detail.id_format) <![CDATA[<=]]> event.high_age
AND (event.eligible_gender IS NULL OR event.eligible_gender = p.gender))
If you want to check some condition (AND EXISTS ... clause) only if some other condition holds (source is MANUAL) and you want to do that in one query instead of:
WHERE (...some condition ...) AND (.. some other condition ... )
IF #source != 'MANUAL'
AND EXISTS (
SELECT 1 ... )
which is not supported as it is not a correct sql syntax you can do:
WHERE (...some condition ...) AND (.. some other condition ... )
AND (
(
(SELECT md.[source]
FROM sports_service.meet.meet_detail md
WHERE md.meet_id = #{meetId}
) = 'MANUAL'
)
OR EXISTS (
SELECT 1
FROM ...
)
)
You need to check if the performance of the resulting query would be satisfactory.
It would be probably better to execute the query that gets the source first and then execute either query with the additional condition or without it depending on the source value. To do that you can generate the query in mybatis using dynamic SQL (including or excluding this additional condition).
As you can't use If inside expression, you can write your sql like this:
DECLARE #source as NVARCHAR(MAX) = (SELECT md.[source] FROM sports_service.meet.meet_detail md WHERE md.meet_id = #{meetId})
WHERE reg.is_waitlist = 0 AND reg.cancelled_dt IS NULL
AND NOT EXISTS (
SELECT
1
FROM
sports_service.meet.meet_invitations i
WHERE
i.meet_id = pmm.meet_id
AND i.sports_person_id = reg.sports_person_id)
AND ( #source <> 'MANUAL'
AND
EXISTS ( SELECT 1 FROM
sports_service.meet.session session
INNER JOIN sports_service.meet.event event ON
event.session_id = session.id
WHERE
pmm.meet_id = session.meet_id
AND sports_service.dbo.fnGetMeetAge(p.birth_dt,
detail.age_up_date,
detail.id_format) >= event.low_age
AND sports_service.dbo.fnGetMeetAge(p.birth_dt,
detail.age_up_date,
detail.id_format) <= event.high_age
AND (event.eligible_gender IS NULL
OR event.eligible_gender = p.gender)))
You can't use IF inside expression.

pass NULL to SQL query

I am getting null result through QueryRunner, but if I execute the query I am getting rows retruned in SQL developer.
ProductId: null
SKUCode:61334a
ServiceResult<List<T>> market = service.getMarketProduct(null,'61334a');
The above mentioned service code will hit DAO layer shown below:
return QueryHelper.queryList( GET_PRODUCTS, new Object[]{ 0 == ProductId? null : ProductId, SKUCode}, this.cs, CPCMarketProductVO.class );
GET_PRODUCTS= SELECT * FROM table WHERE ProductId= nvl(?, ProductId) AND prd_id = nvl(?, SKUCode).
Can someone please tell me why I am getting null results through java code and how results are returned in SQL developer.
I think you are a bit confused in what NVL function is for. Pratically it is useful when the query returns a NULL value and you are doing some kind of operation or aggregate function in it. Instead you are using it to create the request.
Probably you should change the GET_PRODUCTS query in something like
GET_PRODUCTS= SELECT * FROM table WHERE ProductId = ? AND prd_id = ?
When you substitute the ? values with the new Object[]{ 0 == ProductId? null : ProductId, SKUCode} and values ProductId = null, SKUCode = 61334a the query becomes:
GET_PRODUCTS= SELECT * FROM table WHERE ProductId = null AND prd_id = 61334a
returning an empty result set, which should be correct if ProductId is not nullable (I assume is a primary key).
If you instead have NULL ProductIds in your table the result set may not be empty.

Ebean query using setDistinct() does not work

I'm using an ebean query in the play! framework to find a list of records based on a distinct column. It seems like a pretty simple query but the problem is the ebean method setDistinct(true) isn't actually setting the query to distinct.
My query is:
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findList();
In my results I get duplicate artist names.
From what I've seen I believe this is the correct syntax but I could be wrong. I'd appreciate any help. Thank you.
I just faced the same issue out of the blue and can not figure it out. As hfs said its been fixed in a later version but if you are stuck for a while you can use
findSet()
So in your example use
List<Song> allSongs = Song.find.select("artistName").setDistinct(true).findSet();
According to issue #158: Add support for using setDistinct (by excluding id property from generated sql) on the Ebean bug tracker, the problem is that an ID column is added to the beginning of the select query implicitly. That makes the distinct keyword act on the ID column, which will always be distinct.
This is supposed to be fixed in Ebean 4.1.2.
As an alternative you can use a native SQL query (SqlQuery).
The mechanism is described here:
https://ebean-orm.github.io/apidocs/com/avaje/ebean/SqlQuery.html
This is from the documentation:
public interface SqlQuery
extends Serializable
Query object for performing native SQL queries that return SqlRow's.
Firstly note that you can use your own sql queries with entity beans by using the SqlSelect annotation. This should be your first approach when wanting to use your own SQL queries.
If ORM Mapping is too tight and constraining for your problem then SqlQuery could be a good approach.
The returned SqlRow objects are similar to a LinkedHashMap with some type conversion support added.
// its typically a good idea to use a named query
// and put the sql in the orm.xml instead of in your code
String sql = "select id, name from customer where name like :name and status_code = :status";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
sqlQuery.setParameter("name", "Acme%");
sqlQuery.setParameter("status", "ACTIVE");
// execute the query returning a List of MapBean objects
List<SqlRow> list = sqlQuery.findList();
i have a solution for it:-
RawSql rawSql = RawSqlBuilder
.parse("SELECT distinct CASE WHEN PARENT_EQUIPMENT_NUMBER IS NULL THEN EQUIPMENT_NUMBER ELSE PARENT_EQUIPMENT_NUMBER END AS PARENT_EQUIPMENT_NUMBER " +
"FROM TOOLS_DETAILS").create();
Query<ToolsDetail> query = Ebean.find(ToolsDetail.class);
ExpressionList<ToolsDetail> expressionList = query.setRawSql(rawSql).where();//ToolsDetail.find.where();
if (StringUtils.isNotBlank(sortBy)) {
if (StringUtils.isNotBlank(sortMode) && sortMode.equals("descending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
//expressionList.orderBy().asc(sortBy);
}else if (StringUtils.isNotBlank(sortMode) && sortMode.equals("ascending")) {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"asc");
// expressionList.orderBy().asc(sortBy);
} else {
expressionList.setOrderBy("LPAD("+sortBy+", 20) "+"desc");
}
}
if (StringUtils.isNotBlank(fullTextSearch)) {
fullTextSearch = fullTextSearch.replaceAll("\\*","%");
expressionList.disjunction()
.ilike("customerSerialNumber", fullTextSearch)
.ilike("organizationalReference", fullTextSearch)
.ilike("costCentre", fullTextSearch)
.ilike("inventoryKey", fullTextSearch)
.ilike("toolType", fullTextSearch);
}
//add filters for date range
String fromContractStartdate = Controller.request().getQueryString("fm_contract_start_date_from");
String toContractStartdate = Controller.request().getQueryString("fm_contract_start_date_to");
String fromContractEndtdate = Controller.request().getQueryString("fm_contract_end_date_from");
String toContractEnddate = Controller.request().getQueryString("fm_contract_end_date_to");
if(StringUtils.isNotBlank(fromContractStartdate) && StringUtils.isNotBlank(toContractStartdate))
{
Date fromSqlStartDate=new Date(AppUtils.convertStringToDate(fromContractStartdate).getTime());
Date toSqlStartDate=new Date(AppUtils.convertStringToDate(toContractStartdate).getTime());
expressionList.between("fmContractStartDate",fromSqlStartDate,toSqlStartDate);
}if(StringUtils.isNotBlank(fromContractEndtdate) && StringUtils.isNotBlank(toContractEnddate))
{
Date fromSqlEndDate=new Date(AppUtils.convertStringToDate(fromContractEndtdate).getTime());
Date toSqlEndDate=new Date(AppUtils.convertStringToDate(toContractEnddate).getTime());
expressionList.between("fmContractEndDate",fromSqlEndDate,toSqlEndDate);
}
PagedList pagedList = ToolsQueryFilter.getFilter().applyFilters(expressionList).findPagedList(pageNo-1, pageSize);
ToolsListCount toolsListCount = new ToolsListCount();
toolsListCount.setList(pagedList.getList());
toolsListCount.setCount(pagedList.getTotalRowCount());
return toolsListCount;

criteria query ORDER BY yields error. Is this an SQL-SERVER limitation? How could I order by correctly on a complicated criteria query?

I have the following criteria query:
String cat = "H";
Criteria criteria = currentSession().createCriteria(this.getPersistentClass()).
add(Restrictions.ne("category", cat)).
createAlias("employees", "emp").
createAlias("emp.company", "company");
Disjunction disjunction = Restrictions.disjunction();
for(Region r: regions){
disjunction.add(Restrictions.eq("company.region", r));
}
criteria.add(disjunction);
if(status != null) {
criteria.add(Restrictions.eq("status", status));
}
if (period != null) {
criteria.add(Restrictions.eq("period", period));
}
criteria.setProjection(Projections.groupProperty("id")) //this line was added to try to "fix" the error, but it still happened.
criteria.addOrder(Order.asc("id"));
I guess a query that explains my criteria query could be:
select n.* from NOMINATION n
join NOMINEE i on n.NOM_ID = i.NOM_ID
join EMPLOYEE e on e.EMP_ID = i.EMP_ID
join COMPANY c on c.COMPANY_CODE = e.COMPANY_CODE
where n.CATEGORY_CODE!='H' and (c.REGION_ID = ? or c.REGION_ID = ? or c.REGION_ID = ?) and n.STATUS_ID = ? and n.PERIOD_ID = ?
order by n.NOM_ID
What I am trying to do here, is pretty confusing but for the most part it works except when I add this specific line (though the query works fine):
criteria.addOrder(Order.asc("id"));
and then I get error:
java.sql.SQLException: Column "NOMINATION.NOM_ID" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Which I suspect is something that has to do with SQL-SERVER. I am already grouping by id. So what am I doing wrong here, or should I just use HQL?
Your current query seems to be a simple Query which doesn't have any group function used or not a group by query. According to your current requirements you do not have to use this line.
criteria.setProjection(Projections.groupProperty("id")).addOrder(Order.asc("id"));
Or you have to modify your sql statements.

Hibernate field multiple alias

I am having an entity, which has collections field (params). There can be many params. I want to make unique join for each unique param. i.e. p1.id = ? AND p2.id = ? AND p3.id = ? etc.
In Hibernate, when I try to create alias for the same field, it throws exception with message about duplicate alias.
How can I achieve multiple joins for the field?
I am using spring framework, hibernate and postgresql.
Thanks in advance.
I assume that you are using the Criteria API.
If you check the source code of Hibernate you can find the problem here:
CriteriaQueryTranslator#createAssociationPathCriteriaMap()
private void createAssociationPathCriteriaMap() {
Iterator iter = rootCriteria.iterateSubcriteria();
while ( iter.hasNext() ) {
CriteriaImpl.Subcriteria crit = ( CriteriaImpl.Subcriteria ) iter.next();
String wholeAssociationPath = getWholeAssociationPath( crit );
Object old = associationPathCriteriaMap.put( wholeAssociationPath, crit );
if ( old != null ) {
throw new QueryException( "duplicate association path: " + wholeAssociationPath );
}
int joinType = crit.getJoinType();
old = associationPathJoinTypesMap.put( wholeAssociationPath, new Integer( joinType ) );
if ( old != null ) {
// TODO : not so sure this is needed...
throw new QueryException( "duplicate association path: " + wholeAssociationPath );
}
}
}
I'm using Hibernate 3.3.2.
What happens internally is that When you are adding Criterias to your root Criteria Hibernate creates SubCriterias and later fills a Map (check the code below) with all the paths you are trying to use and if it finds a duplication it will throw an exception.
So for example if you are trying to join: entity0.entity1 and later you try to join that again you will get an Exception. It won't work even with an alias because Hibernate doesn't care about them here.
You can work around this if you don't join something twice OR you can use HQL/JPQL. You may check out newer versions of Hibernate but I'm not sure if they fixed this quasi-bug.

Categories