I'm developing software which allows a user to select dynamically one or several users from a database using jpa/Criteria.
Edits/updates:
-I now use a growing predicate with ands. The problem is that i'm not indicating the right field but instead just a string in which java is looking for what th user has entered.
-I still have to check how i can work with pathes as i've been advised to do.
When an user inputs d as PC_Name, d as Name and c as Vorname, the verbose eclipselink shows me this:
[EL Fine]: sql: 2012-07-25 15:44:13.173--ServerSession(24105143)--Connection(13480046)--Thread(Thread[main,5,main])--SELECT PERSONALNUMMER, GEBURTSTAG, GRUPPE, IP, MOBIL, NAME, PC_NAME, TELEFON, VORNAME FROM MITARBEITERTABELLE WHERE ((? LIKE ? AND ? LIKE ?) AND ? LIKE ?)
bind => [PC_Name, %d%, Name, %b%, Vorname, %c%]
This confirms what i'm saying, when i input n as name, i get the entire database because n always belongs to name..
End of edits/updates
Here is the sql version which works:
try{
String selectString ="SELECT * FROM mitarbeitertabelle WHERE ";
selectString=StringModulierung(selectString);
PreparedStatement selectMitarbeiter = con.prepareStatement(selectString);
int i =1;
if(isNameSuche()){selectMitarbeiter.setString (i,this.wc+_Name+this.wc); i++;}
if(isVornameSuche()){ selectMitarbeiter.setString (i, this.wc+_Vorname+this.wc); i++;}
if(isPersonalnummerSuche()){selectMitarbeiter.setString (i, this.wc+_Personalnummer+this.wc); i++;}
if(isPC_NameSuche()){selectMitarbeiter.setString (i, this.wc+_PC_Name+this.wc); i++;}
if(isIPSuche()){selectMitarbeiter.setString (i, this.wc+_IP+this.wc); i++;}
if(isTelefonSuche()){ selectMitarbeiter.setString (i, this.wc+_Telefon+this.wc); i++;}
if(isGeburtstagSuche()){selectMitarbeiter.setString (i, this.wc+_Geburtstag+this.wc); i++;}
if(isGruppeSuche()){ selectMitarbeiter.setString (i, this.wc+_Gruppe+this.wc); i++;}
if(isMobilSuche()){ selectMitarbeiter.setString (i, this.wc+_Mobil+this.wc); i++;}
System.out.println(selectMitarbeiter.toString());
ResultSet ergebnis=selectMitarbeiter.executeQuery();`
with:
public String StringModulierung(String str){
boolean erster=true;
if(isNameSuche()){ str=str.concat("Name LIKE ? ");
erster=false;
}
if(isVornameSuche()){ if(erster){str=str.concat("Vorname LIKE ? ");erster=false;
}else{str=str.concat("AND Vorname LIKE ? ");}
}
if(isPersonalnummerSuche()){ if(erster){str=str.concat("Personalnummer LIKE ? ");erster=false;
}else{str=str.concat("AND Personalnummer LIKE ? ");}
}
if(isPC_NameSuche()){ if(erster){str=str.concat("PC_Name LIKE ? ");erster=false;
}else{str=str.concat("AND PC_Name LIKE ? ");}
}
if(isIPSuche()){ if(erster){str=str.concat("IP LIKE ? ");erster=false;
}else{str=str.concat("AND IP LIKE ? ");}
}
if(isTelefonSuche()){ if(erster){str=str.concat("Telefon LIKE ? ");erster=false;
}else{str=str.concat("AND Telefon LIKE ? ");}
}
if(isGeburtstagSuche()){ if(erster){str=str.concat("Geburtstag LIKE ? ");erster=false;
}else{str=str.concat("AND Geburtstag LIKE ? ");}
}
if(isGruppeSuche()){ if(erster){str=str.concat("Gruppe LIKE ? ");erster=false;
}else{str=str.concat("AND Gruppe LIKE ? ");}
}
if(isMobilSuche()){ if(erster){str=str.concat("Mobil LIKE ? ");erster=false;
}else{str=str.concat("AND Mobil LIKE ? ");}
}
return str;
}
Here's what i've done with jpa:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name_p");
ParameterExpression<String> ip = cb.parameter(String.class,"IP_p");
ParameterExpression<String> pers_num = cb.parameter(String.class,"Personalnummer_p");
ParameterExpression<String> name = cb.parameter(String.class,"Name_p");
ParameterExpression<String> vorname = cb.parameter(String.class,"Vorname_p");
ParameterExpression<String> telefon = cb.parameter(String.class,"Telefon_p");
ParameterExpression<String> geburtstag = cb.parameter(String.class,"Geburtstag_p");
ParameterExpression<String> gruppe = cb.parameter(String.class,"Gruppe_p");
ParameterExpression<String> mobil = cb.parameter(String.class,"Mobil_p");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
TypedQuery<Mitarbeiter2> tq = EM.createQuery(q);
tq.setParameter("PC_Name_p", "PC_Name"); // searches this.getWc()+_Mobil+this.getWc() in PC_Name !
tq.setParameter("IP_p", "IP");
tq.setParameter("Personalnummer_p", "Personalnummer");
tq.setParameter( name/**entered by user*/, "Name"/**should be the field */);
tq.setParameter("Vorname_p", "Vorname");
tq.setParameter("Telefon_p", "Telefon");
tq.setParameter("Geburtstag_p","Geburtstag" );
tq.setParameter("Gruppe_p", "Gruppe");
tq.setParameter("Mobil_p" ,"Mobil");
List<Mitarbeiter2> ergebnis= tq.getResultList();
I've incorporated the two following solutions:
In order to add dynamically where conditions, you can either use a
List where each Predicate is defined like this:
> Predicate p = cb.like(...);
or you can modify dynamically a single Predicate like this:
> Predicate p = cb.conjunction(); for ( filter : filters) {
> p = cb.and(p, cb.like(...)); }
and
When you do q.where you set the WHERE expression.
It does not append, meaning, the last q.where you invoked is the one
set for the query.
What you need to do is build a Boolean Expression (I think ANDs is
what you want).
Then at the and user q.where to set the expression.
Thanks for your help ;) .
Harald
The two problems i had were these:
1) How to build dynamically a query with Criteria , in order to get a query like (in SQL) this(with many different predicates)?
SELECT * FROM mitarbeitertabelle where (1) like (2) and (3) like (4) ...
This means that at runtime, the user can select one or several criteria he'll use to search an mitarbeiter(german for employee).
2)How to set a link to the attributes of my object?
1) In order to do this, you have to build a predicate, using a predicate which is modified at each adding of a new predicate if the criterion is selected.
p= criteriabuilder.and(p, criteriabuilder.like(path object linking to the right attribute, String s used for the search));
2) The right path enables us to have a link to the right attribute. I use it above. Here, the thing is that without pathes, it is not possible to have a link to your attributes so far i know ;) .
After that, you simply have to achieve your sql command by adding the where clause which takes the predicate as a parameter and the select clause which takes the root(where we'll search in the database) as a parameter:
q.where(p);
q.select(mit);
Then , get your results:
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
Theere is no need to fill and use parameterexpression objects, because i am not using parameterexpression objects. The string used to search is set directly in the like clause at runtime execution.
The entire code(with my variables,names,..) is:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
Path<String> pc_name2 = mit.get("PC_Name");
Path<String> ip2 = mit.get("IP");
Path<String> pers_num2 = mit.get("Personalnummer");
Path<String> name2 = mit.get("Name");
Path<String> vorname2 = mit.get("Vorname");
Path<String> telefon2 = mit.get("Telefon");
Path<String> geburtstag2 = mit.get("Geburtstag");
Path<String> gruppe2 = mit.get("Gruppe");
Path<String> mobil2 = mit.get("Mobil");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name2, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip2,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num2, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name2, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname2, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon2, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag2, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe2, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil2, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
Thank you very much for your help #perissf and #aviram-segal ! Don't hesitate to comment if you think something isn't easy to understand in my answer.
When you do q.where you set the WHERE expression.
It does not append, meaning, the last q.where you invoked is the one set for the query.
What you need to do is build a Boolean Expression (I think ANDs is what you want).
Then at the and user q.where to set the expression.
In your equal clauses, you are using this expression:
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name");
Try instead this:
Path<Mitarbeiter2> pc_name = mit.get("PC_Name");
Or, using Metamodel generated classes,
Path<Mitarbeiter2> pc_name = mit.get(Mitarbeiter2_.pc_name);
I cannot test the Path expressions right now, but I am sure that the following works:
q.where(cb.like(mit.get("PC_Name"), pc_name));
or:
q.where(cb.like(mit.get(Mitarbeiter2_.pc_name), pc_name));
In order to add dynamically where conditions, you can either use a List<Predicate> where each Predicate is defined like this:
Predicate p = cb.like(...);
or you can modify dynamically a single Predicate like this:
Predicate p = cb.conjunction();
for ( filter : filters) {
p = cb.and(p, cb.like(...));
}
Finally, if you are comparing strings, don't forget to transform everything to the same case, before doing the comparison.
Related
I am trying to call a select query from my Java Program but i am getting Invalid Numbererror.
I am trying to call the query something like this
code
String[] l_arr = new String[]{"CUSTOMERCUMULATIVELIMIT"};
l_rs = JDBCEngine.executeQuery(MessageFormat.format(
" SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = {0} AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
I am getting query something like this:
Result
SELECT LIMITS, P.PACKAGE_ID
FROM MSTGLOBALLIMITSPACKAGE P, MSTCUSTOMERPROFILE C
WHERE P.PACKAGE_ID = CUSTOMERCUMULATIVELIMIT
AND C.ID_CUST = '00000144'
AND C.ID_ENTITY = 'B001'
AND C.TYPEUSER = 'ECU'
AND C.ID_ENTITY = P.ID_ENTITY
AND P.PACKAGE_ID NOT LIKE '*%'
I am getting the error Invalid number in the line P.PACKAGE_ID = {0}. I gone through and come to know that if i use to_char i can avoid this error. But I am not sure how to use to_char in P.PACKAGE_ID = {0}.
Also PACKAGE_ID is of type Varchar2 and CUSTOMERCUMULATIVELIMIT is a column in MSTCUSTOMERPROFILE of type Number.
Any help or suggestion will be appreciated. Thanks.
just add to_char to your sql, change {0} to to_char({0})
l_rs = JDBCEngine.executeQuery(MessageFormat.format( " SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = to_char({0}) AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
You are working with this line :
WHERE P.PACKAGE_ID = CUSTOMERCUMULATIVELIMIT
As there are no single quotes, SQL consider CUSTOMERCUMULATIVELIMIT as a number, not a string.
Adding quotes should solve this.
l_rs = JDBCEngine.executeQuery(MessageFormat.format(
" SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = '{0}' AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
I don't understand is it possible for me to apply "if-else" statement between two expressions:
public Predicate build(CriteriaBuilder builder, Root<Person> root) {
Expression<BigDecimal> value_a_1 = root.get(value_a_1);
Expression<BigDecimal> value_a_2 = root.get(value_a_2);
Expression<BigDecimal> value_b_1 = root.get(value_b_1);
Expression<BigDecimal> value_b_2 = root.get(value_a_2);
// Here I want to check if one of the _b values is null or 0 (I hope it is correct):
Expression<Boolean> isValueNullOrZero = builder.or(
value_b_1.isNull(), value_b_1.in(BigDecimal.ZERO),
value_b_2.isNull(), value_b_2.in(BigDecimal.ZERO));
// And then I want to do something like this:
Expression<BigDecimal> value_c_1 = isValueNullOrZero ? value_a_1 : value_b_1;
Expression<BigDecimal> value_c_2 = isValueNullOrZero ? value_a_2 : value_b_2;
// etc
...
}
I'm currently working on a fetaure that will allow the system to search public services receipts by the combination of 6 parameters which can be null meaning that receipts shouldn't be filtered by this parameter: accountNumber, amountRangeMin, amountRangeMax, dateRangeMin, dateRangeMax, publicServiceId. However making a method for each combination of the parameters is not an option, I'm thinking that there must be a better way, at first my approach was as following:
On my Service I have this method:
public Map<String,Object> findPublicServiceReceiptsByParams(Integer accountNumber, BigDecimal amountRangeMin,
BigDecimal amountRangeMax, LocalDate dateRangeMin, LocalDate dateRangeMax, Integer publicServiceId) {
Map<String,Object> publicServiceReceipts = new HashMap<String,Object>();
String accountNumberFilter = !(accountNumber==null) ? accountNumber.toString() : "AccountNumberTableName";
String amountRangeMinFilter = !(amountRangeMin==null) ? amountRangeMin.toString() : "table.AmountColumnName";
String amountRangeMaxFilter = !(amountRangeMax==null) ? amountRangeMax.toString() : "table.AmountColumnName";
String dateRangeMinFilter = !(dateRangeMin==null) ? dateRangeMin.toString() : "Table.ReceiptCreationDateColumn";
String dateRangeMaxFilter = !(dateRangeMax==null) ? dateRangeMax.toString() : "Table.ReceiptCreationDateColumn";
String publicServiceIdFilter = !(publicServiceId==null) ? publicServiceId.toString() : "table.publicServiceIdColumn";
publicServiceReceipts = publicServiceReceiptRepository.findPublicServiceReceiptsByParams(accountNumberFilter,
amountRangeMinFilter, amountRangeMaxFilter, dateRangeMinFilter, dateRangeMaxFilter,
publicServiceIdFilter);
return publicServiceReceipts;
}
And then in my repository I had:
final static String FIND_PUBLIC_SERVICES_BY_ARGS = "Select (Insert whatever logic should go in here to select columns from receipts the where clause is the one that matters)"
+ " WHERE ACT.ACT_AccountNumber=:accountNumberFilter\n"
+ " AND PSE.PSE_Id=:publicServiceIdFilter\n"
+ " AND PSR.PSR_CreateDate BETWEEN :dateRangeMinFilter AND :dateRangeMaxFilter\n"
+ " AND PSR.PSR_Amount BETWEEN :amountRangeMinFilter AND :amountRangeMaxFilter\n"
+ " order by PSR.PSR_CreateDate desc";
#Query(nativeQuery = true, value = FIND_PUBLIC_SERVICES_BY_ARGS)
Map<String, Object> findPublicServiceReceiptsByParams(#Param("accountNumberFilter") String accountNumberFilter,
#Param("amountRangeMinFilter") String amountRangeMinFilter,
#Param("amountRangeMaxFilter") String amountRangeMaxFilter,
#Param("dateRangeMinFilter") String dateRangeMinFilter,
#Param("dateRangeMaxFilter") String dateRangeMaxFilter,
#Param("publicServiceIdFilter") String publicServiceIdFilter);
}
My reasoning was that if a parameter was null meant that whoever consumed the Web Service is not interested in that paramater so if that happens I set that variable as the Column Name so that it wouldn't affect in the WHERE clause and in theory make it simpler, but what I found was that It would send the names as Strings so it wouldn't be recognized as an sql statement which was the flaw in my thinking and as I said there must be another way other than writing each method for each combination, I appreciate any help :).
You should use the Criteria API, which was designed for creating dynamic queries. Named queries aren't really meant to be used in this case.
With it you can do something like this:
#PersistenceContext
EntityManager em;
List<YourEntity> method(String argument) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
List<Predicate> predicates = new ArrayList<>();
if (argument == null) {
predicates.add(cb.equal(root.get("yourAttribute"), argument);
}
// rest of your logic goes here
cq.where(predicates.toArray(new Predicate[]{}));
return em.createQuery(cq).getResultList();
}
I found a way to fix this, I did it like this (I'm going to show only the native Query since it's the inly thing that i changed):
DECLARE #actNum varchar(50),#crdNum varchar(50),#pseId varchar(50),#dateMin varchar(50),#dateMax varchar(50),#amountMin varchar(50),#amountMax varchar(50)
SET #actNum = :actNum
SET #crdNum = :crdNum
SET #pseId = :pseId
SET #dateMin = :dateMin
SET #dateMax = :dateMax
SET #amountMin = :amountMin
SET #amountMax = :amountMax
--Whatever Select with joins statement
WHERE ACT.ACT_AccountNumber = CASE WHEN #actNum = 'N/A'
THEN ACT.ACT_AccountNumber
ELSE #actNum END
AND CRD_CardNumber = CASE WHEN #crdNum = 'N/A'
THEN CRD_CardNumber
ELSE #crdNum END
AND PSE.PSE_Id= CASE WHEN #pseId = 'N/A'
THEN PSE.PSE_Id
ELSE #pseId END
AND PSR.PSR_CreateDate >= CASE WHEN #dateMin = 'N/A'
THEN PSR.PSR_CreateDate
ELSE #dateMin END
AND PSR.PSR_CreateDate <= CASE WHEN #dateMax = 'N/A'
THEN PSR.PSR_CreateDate
ELSE #dateMax END
AND PSR.PSR_Amount BETWEEN CASE WHEN #amountMin = 'N/A'
THEN PSR.PSR_Amount
ELSE #amountMin END
AND CASE WHEN #amountMax = 'N/A'
THEN PSR.PSR_Amount
ELSE #amountMax END
ORDER BY PSR.PSR_CreateDate DESC
The backend will send the parameters as either "N/A" (if it shouldn't be used to filter data) or the actual value, this worked fine for me!
I'm having issues properly grouping my query using CriteriaBuilder and Predicates.
I want to create a query that can generate something like:
SELECT * from tableName where columnA = '1234' and (columnB Like '%33%' or columnB Like '%44%')
But what I'm getting (Obviously expected looking at the code) is:
SELECT * from tableName where columnA = '1234' and columnB Like '%33%' or columnB Like '%44%'
Which does not produce the same result as the first query.
Been trying to work around it, but this is my first time working with criteriaBuilder and predicates.
Here's the code:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Foo> criteriaQuery = builder.createQuery(Foo.class);
Root r = criteriaQuery.from(Foo.class);
Predicate predicate = builder.conjunction();
for(Map.Entry<String, String> entry : searchParams.entrySet()){
if((entry.getKey().equalsIgnoreCase("columnK") || entry.getKey().equalsIgnoreCase("columnY") ||
entry.getKey().equalsIgnoreCase("columnZ") || entry.getKey().equalsIgnoreCase("columnJ")) && !Strings.isNullOrEmpty(entry.getValue())){
predicate = builder.and(predicate,
builder.like(r.get(entry.getKey()),
String.format("%%%s%%", entry.getValue().toString())));
}
else if(entry.getKey().equalsIgnoreCase("theDate") && !Strings.isNullOrEmpty(entry.getValue())){
predicate = builder.and(predicate, builder.equal(r.get(entry.getKey()), entry.getValue()));
}
}
//here's where the problem is ... I realize I can use IN, but I also didn't get that to work
boolean isFirstDone = false;
for(String oneId: idStringList){
if(!isFirstDone) {
predicate = builder.and(predicate, builder.equal(r.get("acceptorId"), oneId));
isFirstDone = true;
}
else{
predicate = builder.or(predicate, builder.equal(r.get("acceptorId"), oneId));
}
}
criteriaQuery.where(predicate);
Thank you.
Okay, so I just cracked this after carefully reading this answer https://stackoverflow.com/a/9323183/5038073 The solution is not exactly what I needed but it helped... a lot
I created a path and combined it with my predicate.
Here's what changed:
This:
boolean isFirstDone = false;
for(String oneId: idStringList){
if(!isFirstDone) {
predicate = builder.and(predicate, builder.equal(r.get("acceptorId"), oneId));
isFirstDone = true;
}
else{
predicate = builder.or(predicate, builder.equal(r.get("acceptorId"), oneId));
}
}
became:
Path<Object> path = r.get("acceptorId");
CriteriaBuilder.In<Object> in = builder.in(path);
for (String oneId: idStringList) {
in.value(oneId);
}
predicate = builder.and(predicate, in);
Pretty simple for all the trouble it took me to solve.
Hope this helps someone else too!
i want add some more complicated selections as below on date coloumn
select TO_DATE ('04-JAN-2015','DD-MM-YYYY'), to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'FMDAY') day,
(case when to_char(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'FMDAY') = 'SUNDAY' then to_number(to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'W'))
else ceil((to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'dd') + 1 - to_char(next_day(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'SUNDAY'), 'dd'))/7)
end)+1 week_no
from dual
here breakupFields is list of string which leads to date column
final QueryBuilder distinctDateTimeFilter = new QueryBuilder() {
final List<String> breakupFields = new ArrayList<String>(fields.length);
for (final String f : fields)
if (!Strings.isEmpty(f)) {
breakupFields.add(f);
}
}
final QueryBuilder distinctDateTimeFilter = new QueryBuilder() {
#Override
public CriteriaQuery buildQuery(CriteriaBuilder cb, CriteriaQuery query, Predicate p, List orders, Root rt) {
Expression selection = null;
selection = cb.function("TO_CHAR", String.class, cb.sum(CriteriaQueryUtils.getPath(rt, breakupFields), cb.literal(miliSecToAdd)),
cb.literal("W-MM-YYYY"));
return query.select(selection).distinct(true).where(p).orderBy(orders);
}
}
final List<Object> objs = new ArrayList<Object>(ds.executeQuery(classObject, Object.class, distinctDateTimeFilter, ef, session,
SuperUserSecurityContext.class));
Can any one suggest how to add
(case when to_char(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'FMDAY') = 'SUNDAY' then to_number(to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'W'))
else ceil((to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'dd') + 1 - to_char(next_day(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'SUNDAY'), 'dd'))/7)
end)+1 to criteria builder
You can introduce a column in your Entity marked as
#Formula(value="the expression")
See more here and use the column in the queries.
Or you can define native SQL query with the desired entity class mapped and use fuly native SQL.