I'm having problems creating a proper query using an eclipselink expression when it comes to needing an OR clause. This is my code:
Expression filter = /* filter is not null */;
if (secondStatus != null) {
Integer second = ticketService.getStatusIdByName(secondStatus);
filter = filter.and(
builder.get(Complaint.propertyName.status)
.equal(second)
.or(builder.get(Complaint.propertyName.status)
.equal(status)));
// Also tried the below
// filter = filter.or(builder.get(Complaint.propertyName.status).equal(second));
}
The first way only returned a query including one of the statuses, meanwhile the second (commented out) way returned it's own subquery. Both ways I was getting incorrect results. What is the correct way to incorporate an OR clause into a query?
I figured out what I was doing wrong. I was missing the initial filter in the second statement assuming it would produce the proper SQL automatically.
filter = filter.and(builder.get(Complaint.propertyName.status)
.equal(second)
.or(filter.and(builder.get(Complaint.propertyName.status)
.equal(status))));
This works as intended.
Related
Hi I am using JOOQ to build a SQL statement in my java application. I need to include an or clause in my statement under a certain condition and omit under the other.
e.g.
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(field("q.APPLICATION").eq("APP1"));
I then need to unclude an or part to the query depending on some other variable..
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(field("q.APPLICATION").eq("APP1"))
.or(field("q.APPLICATION").eq("APP2"));
I can't figure out how to do this without having two separate statements, one including the or statement and one without. Thanks in advance.
What you want to do is use the extensions of SelectConditionStep which will allow you to break up the query into individual steps and use a flag as a means to attach only one specific extension of SelectConditionStep to the query.
Given your query and a flag (boolean - to separate the extension of SelectConditionStepto be used) called for e.g. checkBothApps.
boolean checkBothApps = false;
org.jooq.SelectJoinStep<R> joinStep = select(field("q.*"))
.from(table("QUEUES q"));
org.jooq.SelectConditionStep<R> conditionStep = joinStep.where(field("q.APPLICATION").eq("APP1"));
if (checkBothApps) {
// This condition will be added to the join step.
joinStep.or(field("q.APPLICATION").eq("APP2"));
}
Edit: Tested code.
Thanks to Koshux
I did it like this...
Condition whereClause = field("q.APPLICATION").eq("APP1");
if(bothApps){
whereClause = whereClause.or(field("q.APPLICATION").eq("APP2"));
}
org.jooq.Query ps = select(field("q.*"))
.from(table("QUEUES q"))
.where(whereClause);
I'm using the statement below to update/insert some data to a table and, if I run it without parameters, it's fine. However, as soon as I try to execute it using parameters it throws:
SQL0418N - A statement contains a use of an untyped parameter marker, the DEFAULT keyword, or a null value that is not valid.
I've read the error information here, but I'm still struggling with why my statement won't execute.
--This statement works
MERGE Into AB.Testing_Table A
USING (VALUES('TEST', 'P')) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES ('TEST', 'P')
WHEN MATCHED THEN
UPDATE SET TEST_ID = 'TEST'
,"ACTION" = 'P';
--This statement fails with error SQL0418N
MERGE Into AB.Testing_Table A
USING (VALUES(#TEST, #ACTION)) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES (#TEST, #ACTION)
WHEN MATCHED THEN
UPDATE SET TEST_ID = #Test
,"ACTION" = #Action;
Thanks in advance for the help!
Basically, DB2 doesn't know what data types you're sending in on those parameters. I'm guessing you're either on an older version of DB2 (less than 9.7 on Linux/Unix/Windows, or on a Mainframe version older than 10.1), which doesn't do a whole lot of "automatic" type conversion. Or you're sending in NULL values (which still have to be "typed", strange as it sounds).
You can fix the problem by creating your parameter markers as typed parameters (I'm assuming data types here, use what would be appropriate):
MERGE INTO AB.TESTING_TABLE A
USING (VALUES (
CAST(#TEST AS CHAR(4))
,CAST(#ACTION AS CHAR(1))
)) B(TEST_ID, "ACTION")
ON (A.TEST_ID = B.TEST_ID)
WHEN NOT MATCHED THEN
INSERT (TEST_ID, "ACTION")
VALUES (B.TEST_ID, B.ACTION)
WHEN MATCHED THEN
UPDATE SET "ACTION" = B.ACTION
Additionally, since you're using the MERGE, you don't have to use parameters in the UPDATE or INSERT parts, you can refer to the values in the USING table you passed in. Also, since you're matching on TEST_ID, you don't need to include that in your UPDATE statement, since it wouldn't be updated, anyway.
I'm trying to create a query using CriteriaBuilder where I need to have a predicate where the value of the predicate is like the value in the database.
Basically, I need to be able to do the following:
WHERE myTestValue LIKE columnValue
In native queries, it is an option to do that, but using the CriteriaBuilder or NamedQueries, it does not seem to work.
String myValue = "foo#bar.com";
cb.where(cb.like(myValue, root.get(Entity_.email));
Is there an option in JPA to do it like this? Or should I fall back to native queries?
EDIT
I need to be able to check if a given value matches a wildcard entry in database. So the database has a record %#bar.com%, and I need to check if my given value foo#bar.com matches to that record.
I think your params should be other way round:
cb.where(cb.like(root.get(Entity_.email),myValue);
Aditionally you may need to use add this to the second param:
cb.where(cb.like(root.get(Entity_.email),"%"+myValue+"%");
Chris found the answer. First I need to "generate" a parameter.
ParameterExpression<String> senderEmailParameter = cb.parameter(String.class, "senderEmailParameter");
Path<String> senderEmailPath = root.get(Entity_.senderEmail);
Predicate predEmail = cb.like(senderEmailParameter, senderEmailPath);
And then I need to fill the parameter in the query.
q.where(predEmail);
return em.createQuery(q).setParameter("senderEmailParameter", senderEmail).getSingleResult();
This works! Thanks Chris!
I am writing a select query in hql , my task is to activate the bus. First I will get a messege from client as busId#busStatus, so first I look for this perticular busId is active or inactive So I have to write select query but in hibernate query.list() returns list. Here I think list is unnecessary , a single object is enough .
Here is my code ,
String hql="from BusDetailBean where Busid= :busId and bus_status=:busStatus";
Query query = session.createQuery(hql);
query.setParameter("busId", busId);
query.setParameter("busStatus", busStatus);
List<BusDetailBean> busDetails=(List<BusDetailBean>)query.list();
if(busDetails.isEmpty())
{
//my other stuff
}
else
{
//bus ativation stuff
}
My question is the select query returns only one object if list is not empty I have to use for loop in else part. So how can I optimise this code. can anyone help me in this.
You can use query.getSingleResult()
You can use query.setMaxResults(1);
You can get the object at index 0 in the list:
List l = query.list()
if (l.size()>0) {
return l.get(0)
}
I don't think persitence should be mixed with business logic.
What about returning Optional from the persitence layer and whether result is present/absent do something in higher level?
In persistance layer something like:
return query.list()
.stream()
.findFirst()
This, according to docs, will return first result or empty optional if the collection was empty.
And then:
Optional<Bus> optionalBus = repository.find(busId, busStatus);
if (optionalBus.isPresent()) {
something here
} else {
something else
}
by using query.uniqueResult() you don't ensure that if you have many results , then you will get only one of them.
With uniqueResult() you place a guard/contraint at your result set to be aware that this query should always return a unique result.
For this type of problem, the out of the box solution in Hibernate is to use the uniqueResult() method in the Query class:
public Object uniqueResult()
From the Hibernate JavaDocs:
Convenience method to return a single instance that matches the query,
or null if the query returns no results.
Returns: the single result or null
Throws:
NonUniqueResultException - if there is more than one matching result
HibernateException
Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!