JPA Native Query - jpa

I am trying to execute a native query and pass run-time parameters and get the result as a List. When I try to process the Object [], one of the columns fetched is a String. But it comes out as java.lang.Character instead of String. Here is the query below:
SELECT CASE
WHEN (TRUNC(abm.credit_card_expiration_date) BETWEEN trunc(SYSDATE) AND
trunc(last_day(SYSDATE))) THEN
'Expires'
ELSE
'Expired'
END EXP_STATUS,
TO_CHAR(abm.credit_card_expiration_date, 'MM/YY') EXP_DATE
FROM account_billing_methods abm
WHERE abm.account_id = 201103
AND abm.billing_type_id = 1
AND TRUNC(abm.credit_card_expiration_date) <= TRUNC(LAST_DAY(SYSDATE))
The EXP_STATUS column could not be typecasted into String as it is of type Character. Any ideas of why it does not work?
Regards,
-Anand

I had the same problem and changed the select clause of my query to:
EXP_STATUS || '' as EXP_STATUS
Then it is a VARCHAR instead of a CHAR and JPA will return it as a String instead of a Character.
If someone knows a better/more elegant solution, I would appreciate if you could share it.

Related

like and nvl in jpql query - springboot JPA

i am trying to write the below query into spring boot jpql (postgresql db)
first_name
FROM
employees
WHERE
first_name LIKE concat(concat('%',nvl(:key,first_name) ),'%'); --This is oracle style query
Iam trying to write the same logic in JPQL(am new to JPA and JPL , but i know this simple logic ,we can achieve using the implementation less queires , but the above mentioned is a part of a bigger query).
I tried like below. But stuck actually.
#Query("select pe.packageName from PackageEntity pe where " +
"lower(pe.packageName) like " +
"case when :packageName is null then lower(pe.packageName) else concat('%',lower(:packageName),'%') end " )
List<String> getValues( #Param("packageName") String roomIDList);
Error Message is below
org.postgresql.util.PSQLException: ERROR: function lower(bytea) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 190
Honestly , i've tried every possible solution , i can think of. found same error in stackoverflow , but there solution doesn't match, I really want to send the null values in the query , if the input is null then need to ignore the validation, for example if the input parameter is null, then i want to completely ignore the validation.
solution :-
#Query("select pe.packageName from PackageEntity pe where " +
":packageName is null or lower(pe.packageName) like
concat('%',lower(:packageName),'%')" )
The above workaround worked actually.
But I implemented like, In cotroller code
if (search.getPackageName() == null) {
LOGGGER.info("Input Name is NULL");
search.setPackageName("==!##$%^&*()!##$%^&*()==");
LOGGGER.info("Input Name is set to Default " + search.getPackageName());
}
searchValue = repoPackage.getPackageAll(search.getPackageName());
in repo, where condition is like below - Not sure , if the solution is the best, but it worked. Like this I avoided sending any null value to jpa.
where
(('==!##$%^&*()!##$%^&*()==' = :packageName)
or lower(pd.package_name) like concat('%', lower(:packageName), '%'))

How to pick up data from row and put it into tPostgresqlInput?

I have a requets which giving me an ids. I need to iterate them into another request, so I have a sheme like this: scheme
In tPostgresqlInput I have this code rc.id = upper('18ce317b-bf69-4150-b880-2ab739eab0fe') , but instead of id I need to put smthn like globalMap.get(row4.id). How did I do this?
Apparently this is a syntax issue
Try with :
"select * FROM table LEFT JOIN table on parameter JOIN table on parameter
WHERE 1=1 AND
column = 'content'
AND upper(rc.id) = upper('"+((String)globalMap.get("row4.id")) +"')"
Expressions in tDBInput should always begin and end with double quotes.
Don't forget to cast globalMap.get() with the type of your element (here I put String)
.equals is not a DB function but a java function. I have replaced it with '='
Let me know if it's better

How to use tSQL to match and remove everything after a string?

How can I use tSQL to find a string, and if it exists, return everything before that string?
i.e. in the example below, in an ETL process, how would we take the column from source, identify the string ?uniquecode= and therefore remove that, and everything else after it, in the SELECT statement for the sink column?
How can I best modify this tSQL statement below to return the values in SinkPageURL column above?
SELECT SourcePageURL FROM ExampleTable
I have attempted a Fiddle here - http://sqlfiddle.com/#!18/3b60a/4 using the below statement. It is disregarding the values where '?uniquecode=' does not exist though, and also leaves the '?' symbol. Need this to work with MS SQL Server '17.
Somewhat close, but no cigar. Help appreciated!
SELECT LEFT(SourcePageURL, CHARINDEX('?uniquecode=', SourcePageURL)) FROM sql_test
Try this query:
SELECT
CASE WHEN CHARINDEX('?uniquecode=', SourcePageURL) > 0
THEN SUBSTRING(SourcePageURL,
1,
CHARINDEX('?uniquecode=', SourcePageURL) - 1)
ELSE SourcePageURL END AS new_source
FROM sql_test;
If you instead wanted to update the source URLs in your example using this logic, you could try the following:
UPDATE sql_test
SET SourcePageURL = SUBSTRING(SourcePageURL,
1,
CHARINDEX('?uniquecode=', SourcePageURL) - 1)
WHERE SourcePageURL LIKE '%?uniquecode=%';

How to get only specific rows on DB, when date range fits SQL condition on a 'tsrange' datatype? [duplicate]

I have this query:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', some_id)
I get the following error:
TypeError: 'int' object does not support indexing
some_id is an int but I'd like to select indicators that have some_id = 1 (or whatever # I decide to put in the variable).
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', [some_id])
This turns the some_id parameter into a list, which is indexable. Assuming your method works like i think it does, this should work.
The error is happening because somewhere in that method, it is probably trying to iterate over that input, or index directly into it. Possibly like this: some_id[0]
By making it a list (or iterable), you allow it to index into the first element like that.
You could also make it into a tuple by doing this: (some_id,) which has the advantage of being immutable.
You should pass query parameters to execute() as a tuple (an iterable, strictly speaking), (some_id,) instead of some_id:
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id,))
Your id needs to be some sort of iterable for mogrify to understand the input, here's the relevant quote from the frequently asked questions documentation:
>>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct
This should work:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id, ))
Slightly similar error when using Django:
TypeError: 'RelatedManager' object does not support indexing
This doesn't work
mystery_obj[0].id
This works:
mystery_obj.all()[0].id
Basically, the error reads Some type xyz doesn't have an __ iter __ or __next__ or next function, so it's not next(), or itsnot[indexable], or iter(itsnot), in this case the arguments to cursor.execute would need to implement iteration, most commonly a List, Tuple, or less commonly an Array, or some custom iterator implementation.
In this specific case the error happens when the classic string interpolation goes to fill the %s, %d, %b string formatters.
Related:
How to implement __iter__(self) for a container object (Python)
Pass parameter into a list, which is indexable.
cur.execute("select * from tableA where id =%s",[parameter])
I had the same problem and it worked when I used normal formatting.
cursor.execute(f'
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" ={some_id};')
Typecasting some_id to string also works.
cursor.execute(""" SELECT * FROM posts WHERE id = %s """, (str(id), ))

Passing a null parameter to a native query using #Query JPA annotation

In a Spring Boot application, I have a SQL query that is executed on a postgresql server as follows :
#Query(value = "select count(*) from servers where brand= coalesce(?1, brand) " +
"and flavour= coalesce(?2, flavour) ; ",
nativeQuery = true)
Integer icecreamStockCount(String country, String category);
However,
I get the following error when I execute the method :
ERROR: COALESCE types bytea and character varying in PostgreSQL
How do I pass String value = null to the query?
**NOTE : ** I found that my question varied from JPA Query to handle NULL parameter value
You need not coalesce, try this
#Query("select count(*) from servers where (brand = ?1 or ?1 is null)" +
" and (flavour = ?2 or ?2 is null)")
Integer icecreamStockCount(String country, String category);
When I encounted this error, I ended up using a combination of OR and CAST to solve the issue.
SELECT COUNT(*)
FROM servers
WHERE (?1 IS NULL OR brand = CAST(?1 AS CHARACTER VARYING))
AND (?2 IS NULL OR flavour = CAST(?2 AS CHARACTER VARYING))
This works even if ?1, ?2, brand and flavor are all nullable fields.
Note that passing null for ?1 means "all servers regardless of brand" rather than "all servers without a brand". For the latter, you could use IS DISTINCT FROM as follows.
SELECT COUNT(*)
FROM servers
WHERE (CAST(?1 AS CHARACTER VARYING) IS NOT DISTINCT FROM brand)
AND (CAST(?2 AS CHARACTER VARYING) IS NOT DISTINCT FROM flavour)
Finally, certain parameter types such as Boolean cannot be cast in SQL from BYTEA to BOOLEAN, for those cases you need a double cast:
SELECT COUNT(*)
FROM servers
WHERE (?1 IS NULL OR is_black = CAST(CAST(?1 AS CHARACTER VARYING) AS BOOLEAN))
In my eyes this is a problem in Hibernate which could be solved by passing Java null parameters as plain SQL NULLs rather than interpreting null as a value of type BYTEA.
If you really need to use native query, there is a problem because it's an improvement not implemented yet, see hibernate. If you don't need to use native you can do (where ?1 is null or field like ?1). Assuming you do need native,
you may treat the String before by setting this empty and then calling the repository and this one would be like:
#Query(value = "select count(*) from servers where (?1 like '' or brand like ?1) " +
"and (?2 like '' or flavour like ?2)",
nativeQuery = true)
Integer icecreamStockCount(String country, String category);
There is always javax.persistence.EntityManager bean as option for native query situations and I recommend it instead of previous approach. Here you can append to your query the way you want, as follows:
String queryString = "select count(*) from servers ";
if (!isNull(country)) queryString += "where brand like :country";
Query query = entityManager.createNativeQuery(queryString);
if (!isNull(country)) query.setParameter("country", country);
return query.getResultList();
Observations:
Newer versions have improved this '+' concatenation Strings. But you can build your queryString the way you want with StringBuilder or String Format, it doesn't matter.
Be careful with SQL injection, the setParameter method avoid this kind of problem, for more information see this Sql Injection Baeldung
So this is not the exact answer to the question above, but I was facing a similar issue, I figured I would add it here, for those that come across this question.
I was using a native query, in my case, it was not a singular value like above, but I was passing in a list to match this part of the query:
WHERE (cm.first_name in (:firstNames) OR :firstNames is NULL)
I was getting the bytea error, in the end I was able to send an empty list.
(null == entity.getFirstName()? Collections.emptyList() : entity.getFirstName())
In this case, sending the empty list to the resolver worked, where as null did not.
hope this saves you some time.
null parameters are not allowed before Hibernate 5.0.2.
See https://hibernate.atlassian.net/browse/HHH-9165
and the replies to https://www.postgresql.org/message-id/6ekbd7dm4d6su5b9i4hsf92ibv4j76n51f#4ax.com