Reputation: 1
I want to execute a SELECT
query based on various the conditions that a user can specify through an HTML form. Each condition in the query maps to an appropriate field in the HTML form. If no value is specified for a field, the corresponding condition can be skipped in the query.
The fully formed query is shown below:
select
d
from
TotalInventoryTransaction d
where
d.transactionDate between ?1 and ?2
and d.material=?3
and d.shipmentOrder between ?4 and ?5
and d.source = ?6
and d.destination= ?7
The Spring Data JPA repository method is as follows:
@Query(FILTER_DATA_QUERY)
List<TotalInventoryTransaction> getFilteredData(Date dateFrom
, Date dateTo
, Long material
, Long stoFrom
, Long stoTo
, String source
, String destination);
I would like to pass FILTER_DATA_QUERY
to this method in such a way that if a method parameter is not specified, its corresponding clause is skipped in the executed query.
Please suggest how this can be achieved.
Upvotes: 0
Views: 1008
Reputation: 1
I am now building a query statement by using string buffer according to condition it is working.. if value is not null then I am appending it into the query else I am not appending..
one section is like this..
StringBuffer queryBuff = new StringBuffer();
queryBuff
.append("select * from table_name where");
try {
if ((dateFromStr != null && dateFromStr != "")
&& (dateToStr != null && dateToStr != "")) {
dateFrom = df.parse(dateFromStr);
dateTo = df.parse(dateToStr);
queryBuff.append(" transaction_date between " + "\'" + dateFrom
+ "\'" + "and" + "\'" + dateTo + "\'");
} else {
queryBuff.append("");
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (materialName != null && materialName != "") {
if ((dateFromStr == null || dateFromStr == "")
&& (dateToStr == null || dateToStr == ""))
{
queryBuff.append(" material=" + "\'" + materialName + "\'");
} else {
queryBuff.append(" and ");
queryBuff.append(" material=" + "\'" + materialName + "\'");
}
}
Upvotes: 0
Reputation: 3063
If you are using Spring-data-Jpa I would like to suggest you to use criteria API. Check out the docs here. You can use predicates to create dynamic where clauses. I created an example to show you the use.
Table:-
@Entity
public class Test {
@Id private Long id;
String attributeOne;
String attributeTwo;
...
}
The actual query
//Params from the method
String param1 = "1";
String paramNull = null;
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery cq = qb.createQuery();
Root<Test> variableName = cq.from(Test.class);
//Creating Predicates
List<Predicate> predicates = new ArrayList<Predicate>();
//Adding predicates when params are not null
if (param1 != null) {
predicates.add(
qb.equal(variableName.get("attributeOne"), param1));
}
if (paramNull != null) {
predicates.add(
qb.equal(variableName.get("attributeTwo"), paramNull));
}
//Actual query
cq.select(variableName)
.where(predicates.toArray(new Predicate[]{}));
//executing the query
em.createQuery(cq).getResultList();
Hope this helps.
Upvotes: 1
Reputation: 20135
You simply need to make sure that when a parameter value is supplied, that value is considered for the query and when it is not specified, the corresponding column value is considered instead.
The following hard-coded JPA query will work:
select
d
from
TotalInventoryTransaction d
where
d.transactionDate >= coalesce(?1, d.transactionDate)
and d.transactionDate <= coalesce(?2, d.transactionDate)
and d.material = coalesce(?3, material)
and d.shipmentOrder >= coalesce(?4, d.shipmentOrder)
and d.shipmentOrder <= coalesce(?5, d.shipmentOrder)
and d.source = coalesce(?6, d.source)
and d.destination = coalesce(?7, d.destination)
COALESCE
is a standard ANSI-SQL function that has been adopted into the JPA Query Language as well. Clauses like d.material = coalesce(?3, material)
can be understood in plain English as if a (non-null) value is specified, match the specified value against the values in the material column; otherwise, match the column with its own value
. This way, whenever a particular value is not specified, the values in the corresponding column will be compared against themselves, always yielding a match for that particular column, as required.
I have replaced the between
operator with individual operators with the assumption that the user may end up passing only one of the date pairs.
Upvotes: 1