Criteriabuilder like, how to do it for Long? - postgresql

i try use "like" method from Criteriabuilder for get all record based on pattern " 10% ".
I want get record where ID is - 101, 10002, 1003,1000 etc...
I've use this code:
Predicate p = cb.like(r.<String>get("ID").as(String.class), "10%")
but i got Exception where i see what postgres can't execute query like this:
SELECT ID, NAME, SOMETHING FROM TABLE WHERE ID LIKE 10%
That is JPA (Glassfish 4.x) generate wrond query.
Right query must like that :
SELECT ID, NAME, SOMETHING FROM TABLE WHERE CAST (ID as TEXT) LIKE '10%'
How to build query via Criteria API that i got a right query for postgres ?
Updated:
I try write a CAST function :
Expression<String> postgresqlCastFunction = cb.function("CAST", String.class, r.<String>get("ID").as(String.class));
Predicate p = cb.like(postgresqlCastFunction, "10%");
but got a query like this :
FROM TABLE WHERE (CAST(ID) LIKE ?)
, so, how to add need expression in function for this right result -
FROM TABLE WHERE (CAST(ID as TEXT) LIKE ?) ..

An example implementation using PostgreSQL native TO_CHAR function may look as follows:
JPQL
SELECT r FROM Records r
WHERE FUNCTION('TO_CHAR', r.ID, 'FM9999999999') LIKE :pattern
Criteria API
Path<String> id = r.get("ID");
Expression<String> format = cb.literal("FM9999999999");
Expression<String> function= cb.function("TO_CHAR", String.class, id, format);
ParameterExpression<String> pattern = cb.parameter(String.class, "pattern");
Predicate like = cb.like(function, pattern);
cq.where(like);
also you can build the query as an one-liner:
cq.where(cb.like(cb.function("TO_CHAR", String.class, r.get("ID"), cb.literal("FM9999999999")), cb.parameter(String.class, "pattern")));
Execute the above query:
Query q = em.createQuery(cq).setParameter("pattern", "10%");

Related

Count in Spring Data JPQL join query throwing IllegalArgumentException

I have a query using JPQL in the annotation #Query in Spring Data which looks like below
#Query(value = "select distinct a from EntityA as a left join fetch a.listEntityB as b where ...")
public List<EntityA > find....(#Param("") String value, Pageable pageable);
Now I need to know the total number of records of the query. As Pageable is giving me partial list, I am writing another count query without the Pageable. My count query looks like below:
#Query(value = "select count(distinct a) from EntityA as a left join fetch a.listEntityB as b where ...)
public long count...(#Param("") String value);
However, I am getting "IllegalArgumentException: Validation failed for query" error from this query to count the records. When I change the count query to "select count(distinct a) from EntityA" , it works fine. I am not sure what is the problem when I use the join. I did not get any helpful documents so far. Is there any better solution to get the total number of records for the Pageable query.
Put the CountQuery in the same annotation as the query itself. So
#Query(value = "select ...", countQuery = "select count..")
public List<EntityA > find....(#Param("") String value, Pageable pageable);
Also remove the "fetch" from the countQuery.
To get the total records, you can just reference the page.getTotalElements() to return the total number of records.

Use array of ints parameter in FromSQL query and Where In clause

I have a list of ints:
var ids = new List { 10, 20 };
And I need to find Users with that ids:
context.Users.FromSqlInterpolated($#"
select Users.*
where Users.Id in ({String.Join(',', ids)})"
But I get the following error:
'Conversion failed when converting the nvarchar value '10, 20' to data type int.'
How can I use such a parameter?
Using Interpolated method is not appropriate here, because {String.Join(',', ids)} defines single string placeholder, hence EF Core binds single nvarchar parameter with value '10,20', so the actual SQL is like this
select Users.*
where Users.Id in ('10,20')
which is invalid, hence the exception.
You should use Raw method instead. Either
var query = context.Users.FromSqlRaw($#"
select Users.*
where Users.Id in ({String.Join(',', ids)})");
which will embed literal values
select Users.*
where Users.Id in (10,20)
or if you want to parameterize it, generate parameter placeholders like {0}, {1} etc. inside the SQL and pass values separately:
var placeholders = string.Join(",", Enumerable.Range(0, ids.Count)
.Select(i => "{" + i + "}"));
var values = ids.Cast<object>().ToArray();
var query = context.Users.FromSqlRaw($#"
select Users.*
where Users.Id in ({placeholders})", values);
which would generate SQL like this
select Users.*
where Users.Id in (#p0,#p1)
If you need to combine .FromSql() and SQL WHERE x IN () then perform a second operation on the output IQueryable<T> of the .FromSql() call.
var ids = new List { 10, 20 };
var query = context.Users.FromSqlInterpolated(
$#"select *
from Users");
if (ids?.Count > 0)
{
query = query.Where(user => ids.Contains(user.Id));
}
Resultant SQL approximates to:
select * from (
select *
from Users
) u
where u.Id in (10,20)
No invalid SQL if ids is empty
No empty result if ids is empty string (I was working with a string data type)

Select new list of subquery in hql

I am trying to use the subquery in the attributes section.
This works fine when the subquery returns only one result. Otherwise it shows an error.
[2019-12-30 11:24:26] [21000] ERROR: more than one row returned by a subquery used as an expression
#Query("select new com.example.rest.ShiftResponse(s.id, s.displayTitle, s.startTime, s.endTime, s.max, (select comm from ShiftGroup sg inner join sg.committee comm where sg.shift.id = s.id)) from Shift s where s.event.id = ?1")
Here's the constructor's signature
public ShiftResponse(Long id, MultilangText displayTitle, LocalDateTime startTime, LocalDateTime endTime, Integer max, List<Committee> committees) {
Is there any way other than this to specify that I want that parameter to be a List?
Have you checked this link ? HQL new List(..) within new Object(..)
It seems to me it was a similar question. Does it answer your question ?

how to call spring jap query none parameters

I use spring data jpa with native query
I have already some query like this
How to use native query none parameter.
String q="SELECT t1.blockNumber-1 FROM someTAble t1 LEFT JOIN someTAble t2 ON t2.blockNumber = t1.blockNumber-1 WHERE t2.blockNumber IS NULL AND t1.blockNumber> 0 ORDER BY t1.blockNumber";
#Query(value = q,nativeQuery = true)
List<Entity> findByBlockNumberIs();
they are occur errors Column 'sequence' not found.
That query means are when i insert some Contiguous data int value then i find missing data.
But
this query working
SELECT *,t1.blockNumber-1 FROM someTAble t1 LEFT JOIN someTAble t2 ON t2.blockNumber = t1.blockNumber-1 WHERE t2.blockNumber IS NULL AND t1.blockNumber> 0 ORDER BY t1.blockNumber
The difference between the two queries is whether there is a '*' or not
how to change simple to my query.
How to i changed error
OR How to use spring data jpa predicate
QEntity qBe1= QEntity .blockEntity;
QEntity qBe2= QEntity .blockEntity;
build.and(qBe2.blockNumber.eq(be.getBlockNumber()-1))
.and(qBe2.blockNumber.isNull().and(qBe1.blockNumber.gt(0)));
is predicate can use left join?
well...
use this.
List<Integer> findByBlockNumber()

Get count from query

I am using mysql 5.5 with openjpa 2.3.0.
I have entities with namedQueries (generated in netbeans - I would like to be able to use this), for example:
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
#NamedQuery(name = "User.findByGender", query = "SELECT u FROM User u WHERE u.gender = :gender")
I am creating restfull aplication with paged results. I would like to return for every paged result the Content-Range header as 1-20/250 where 20 is pagesize, 250 total count.
I tried to create a query
entityManager.createNativeQuery("SELECT count(1) FROM (" + namedQuery.toString() + ") as foo;");
where I could dynamicaly insert any named query and return the count without returning the result list -> it should be faster.
When I execute this, exception occurs
SQL state 42S22: Unknown column 'u' in 'field list'
Executing the query itself in entitymanager is ok.
Can I use the entity manager or criteria builder to create a query for counting results without returning the result list (and without writing for every namedQuery a count duplicate)? thank you for helping.
You are mixing JPQL with native queries. JPQL says SELECT u FROM entity u, SQL would be SELECT * FROM entity u or SELECT col1,col2,col3 FROM entity u
You could write a JPQL named query counting the stuff, e.g. SELECT COUNT(u) FROM entity u. A getSingleResult() would then return an Object[], whose first element contains the count.
Not nice but working. Why do You have to query for the number anyway? Pagination means next = lastindex+pagesize. if next < lastindex+pagesize, the end is reached.