Casting Integer to String in JPQL - jpa

I want to have a JPQL query that may look like:
entityManager.createQuery("Select a.* from A a WHERE CAST(a.num AS TEXT) LIKE '%345%' ", A.class);
where a.num is an integer. I want to cast this to String to use the LIKE criteria.
However above casting doesnt work in JPQL. Any idea about how can I implement this?

Could you be more specific, what your problem is? Do you have some kind of error or it the result of the query is just wrong?
Because this code works fine for me:
session.createQuery("from MyObject where CAST(id as text) like :id").setParameter("id", "%1").getResultList();
I am using Hibernate 5.2 and Postgresql 9.5.
Also, if you are having trouble understanding what goes wrong, you could try editing hibernate.cfg.xml or whatever configuration file you are using to make Hibernate show queries it sends, by doing something like this:
<property name="hibernate.show_sql">true</property>

I also have the same need. This should work with JPA 2.0 and Hibernate 5.0.2:
entityManager.createQuery(
"Select a.* from A a WHERE CONCAT(a.num, '') LIKE '%345%' ", A.class);

From hibernate document, "cast(... as ...)", where the second argument is the name of a Hibernate type. According list of Hibernate Types it should be string (case sensitive!).
So request should be:
entityManager.createQuery("select a.* from A a WHERE CAST(a.num AS string) LIKE '%345%' ", A.class);
Was taken and checked from Caused by: org.hibernate.QueryException: Could not resolve requested type for CAST : INT answer.

You can simply use CAST(num as string). It worked for me

Well you can use to_char() function in the select clause but, you will need to select all the a.num field separately and not with *.
And in postgresql you will need to specify a mask for to_char()function, so it would be to_char(field, mask), for example we can supply 'FM999999999999999999' as a mask to accept the maximum possible digits.
Your query would be something like this:
Select *, to_char(a.num, 'FM999999999999999999') as num from A a WHERE num LIKE '%345%'
You can take a look at Postgresql Data Type Formatting Functions for further details.
To write the query in your code with EntityManager you can create a native query using .createNativeQuery() method, this is how should be your code:
em.createNativeQuery("Select *, to_char(a.num, 'FM999999999999999999') as num from A a WHERE num LIKE '%345%'");

The correct query is :
entityManager.createQuery("Select a.* from A a WHERE CAST(a.num AS String) LIKE '%345%' ", A.class);

Related

PostgreSQL, allow to filter by not existing fields

I'm using a PostgreSQL with a Go driver. Sometimes I need to query not existing fields, just to check - maybe something exists in a DB. Before querying I can't tell whether that field exists. Example:
where size=10 or length=10
By default I get an error column "length" does not exist, however, the size column could exist and I could get some results.
Is it possible to handle such cases to return what is possible?
EDIT:
Yes, I could get all the existing columns first. But the initial queries can be rather complex and not created by me directly, I can only modify them.
That means the query can be simple like the previous example and can be much more complex like this:
WHERE size=10 OR (length=10 AND n='example') OR (c BETWEEN 1 and 5 AND p='Mars')
If missing columns are length and c - does that mean I have to parse the SQL, split it by OR (or other operators), check every part of the query, then remove any part with missing columns - and in the end to generate a new SQL query?
Any easier way?
I would try to check within information schema first
"select column_name from INFORMATION_SCHEMA.COLUMNS where table_name ='table_name';"
And then based on result do query
Why don't you get a list of columns that are in the table first? Like this
select column_name
from information_schema.columns
where table_name = 'table_name' and (column_name = 'size' or column_name = 'length');
The result will be the columns that exist.
There is no way to do what you want, except for constructing an SQL string from the list of available columns, which can be got by querying information_schema.columns.
SQL statements are parsed before they are executed, and there is no conditional compilation or no short-circuiting, so you get an error if a non-existing column is referenced.

OpenJpa how to find length of string in JPQL

I am using
length(ze.string)>2 in openJpa query. but i am getting
SQLCODE=-440, SQLSTATE=42884, SQLERRMC=CHAR_LENGTH;FUNCTION, DRIVER=3.53.95 {prepstmnt 1776269692 SELECT t0.f1, t0.f2, t0.f3, t0.f4, t0.f5, t0.f6, t0.f7, t0.f8, t0.f9, t0.f10, t0.f11, t0.f12, t0.f13, t0.f14, t0.f15, t0.f16, t0.f17 FROM table t0 WHERE (t0.f1 = ? AND CHAR_LENGTH(?) > ? AND .....
In plain query when i do length operation i am getting record but using jpa its not working. I looked Here used size it doesn't work. and the field is varchar and db2. trying from past 1 hour.
DB2 requires use of the SQL function LENGTH, yet OpenJPA seems to be incorrectly converting your JPQL to use SQL function CHAR_LENGTH (hence the error message - not that DB2 gives out clear messages saying what is wrong, who knows what SQLCODE=-440 is without having to search!!).
Raise a bug on your JPA provider.
See https://www.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000818.html
You would need to give more details about your entity, persistence.xml, and query to get to the bottom or this. However, I do not see how OpenJPA would use CHAR_LENGTH instead of LENGTH for DB2. Let me explain. If you look at DBDictionary here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?view=markup
You can see it defines something called "stringLengthFunction" as follows:
public String stringLengthFunction = "CHAR_LENGTH({0})";
This is the string length function which should be used for each individual dictionary (i.e. Database config). However, for DB2, the AbstractDB2Dictionary, see here:
https://svn.apache.org/viewvc/openjpa/branches/2.2.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/AbstractDB2Dictionary.java?view=markup
overrides this as follows:
stringLengthFunction = "LENGTH({0})";
Given this, for DB2, LENGTH should be used. I took the following simple query:
"select me.id from MyEntity me where length(me.name)>2"
And executed it on OpenJPA using DB2, and I got this:
SELECT t0.ID FROM MYENTITY t0 WHERE (CAST(LENGTH(t0.ID) AS BIGINT) > CAST(? AS BIGINT)) [params=(long) 2]
Thanks,
Heath Thomann

PostgreSQL function round and JPA/Hibernate

I have a query which is executed from java application like this:
Query query = getEntityManager().createQuery(hql);
The query looks like this:
String hql = "select * from table a where round(column1, 3) = round(parameter, 3)";
Here column1 is of type Double. The value it holds is like 143.02856666. I need to retain the value as it is, but for some business logic just need to round and compare.
The initial database configured was H2 and this worked fine. Now the database has been changed to Postgres and this query now errors out.
ERROR: function round(double precision, integer) does not exist Hint: No function matches the given name and argument types. You might
need to add explicit type casts.
The round() function in Postgres takes a numeric datatype and needs a cast.
The below query works fine if executed directly in Postgres console.
select * from table a where round(cast(column1 as numeric), 3) = round(cast(parameter as numeric), 3);
The same from java application errors out.
java.lang.IllegalArgumentException: org.hibernate.QueryException: Could not resolve requested type for CAST : numeric
Also tried Query query = getEntityManager().createNativeQuery(hql);
This results in a new error.
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: syntax error at or near "where"
If I debug, this errors out when the below line is executed.
List resultList = query.getResultList();
How do I rewrite the query so that it works against Postgres ?
What you are doing with Query query = getEntityManager().createQuery(hql); is calling a jpql-query, which does not support all db-functions like round(v numeric, s integer).
Two Suggestions:
Use BETWEEN and maintain jpql-mapping
Write a NativeQuery -> Query query = em.createNativeQuery(queryString);
Your queryString just has to be altered by your parameters.

oracle evalname function equivalent in postgres

Oracle supports dynamic XMLElement name with evalname function. Is there a similar feature in postgres to get the XMLElement name dynamically instead of using constant?
Example in ORACLE:
select xmlelement(evalname(ENAME),EMPNO) from EMP;
This statement will result in list of enames as separate xml elements.
<SMITH>7369</SMITH>
<ALLEN>7499</ALLEN>
<WARD>7521</WARD>
Not sure if postgres has something similar.
Thanks.
I was able to get a workaround to construct xml with dynamic element names in Postgres using execute format. Posting this just in case if anyone had same issue.
execute format('SELECT XMLElement(NAME %I, $1)', emp_name) USING empno from emp;
<SMITH>7369</SMITH>
<ALLEN>7499</ALLEN>
Same worked with XMLForest and having XMLAttributes inside XMLElement.
There is no such function as far as I know.
The closest you can get is adding an attribute with the empname:
select xmlelement(name emp, xmlattributes(empname), empno)
from emp;
Generates:
<emp empname="Smith">7369</emp>
<emp empname="Allend">7499</emp>
<emp empname="Ward">7521</emp>
Personally I would find that format much easier to parse e.g. in XSLT or an XML parser. Because in order to process a tag you would need to know the tag name, which you don't if the tag changes for each row - but this might just be me.

How to COUNT(*) in Slick 2.0?

According to the Slick 2.0 documentation,
to get the count of rows in a table:
val q1 = coffees.length
// compiles to SQL (simplified):
// select count(1) from "COFFEES"
However, it turns out that coffees.length is of type Column[Int].
How does one execute the query and get the value?
I just had this same problem upgrading to slick 2.0. I forget where the exact method lives, but the generic .run seems to work for me, i.e.
coffees.length.run
StaticQuery.queryNA[Int]("select count(*) from \"" + TableName + "\"").first
Quotes are needed if your table name is not upper case.
Try coffees.length.first should execute and return Int
Sorry, indeed, in the slick 1.0 there was first method to do this, in Slick 2.0 they get rid of it in favor of more generic run.
The function to execute query is
coffees.length.run