This question already has answers here:
Dynamic spring data jpa repository query with arbitrary AND clauses
(4 answers)
Closed 3 years ago.
Currently I'm unable to know the fields that will be within the SQL where clause (think adhoc) when creating the native SQL in my spring #Query. Therefore I'm passing in the entire where clause.
If I output the SQL to the console and paste it in to my sql editor I'm able to receive a valid resultset.
SELECT * FROM lorder WHERE order_id = 1196077
Last SQL output to the console was:
Hibernate:
/* dynamic native SQL query */ SELECT
*
FROM
lorder
WHERE
?
and the where clause value being passed in to the #query is:
order_id = 1196077
This is what I am currently doing which is not working.
#Query(
value = "SELECT * FROM lorder WHERE :where",
nativeQuery = true)
List<OrderEntity> listSelected(#Param("where") String where);
Not sure if passing the entire where clause is possible but I'm expecting a list. However I'm currently getting an empty collection.
Since using the #Query annotation you can only use named parameters (your :where) or ordinal parameters (e.g. ?1, ?2) of a specific Java-type, it's not possible to inject partial SQL-expressions.
However you could use a TypedQuery to add partial SQL to a query:
public List<OrderEntity> getOrdersUsingWhereClause(EntityManager em, String whereClause) {
TypedQuery<OrderEntity> query = em.createQuery(
"SELECT o FROM lorders o WHERE " + whereClause,
OrderEntity.class);
return query.getResultList();
}
See https://www.objectdb.com/java/jpa/query/parameter#Parameters_vs.Literals
The JPA's criteria query gives you more power to control where clause along with many other supported functionalities.
List of functions : https://en.wikibooks.org/wiki/Java_Persistence/Criteria
Criteria Queries : https://www.baeldung.com/hibernate-criteria-queries
Learn more about criteria query and criteria builder here
Related
I use spring boot, and I want to add 1 year to a specific column in mysql database
String queryRecherche = "UPDATE myTable t SET t.dateDebut = DATE_ADD(t.dateDebut, INTERVAL 1 YEAR) WHERE.id = 3 ";
Query query = em.createQuery(queryRecherche);;
query.executeUpdate();
But I get the folowing error :
org.hibernate.query.sqm.ParsingException: line 1:66 no viable alternative at input 'DATE_ADD(t.dateDebut,INTERVAL1'
Have you please any suggestions to do this.
You're using Hibernate 6 (I can tell by the error message), so the correct HQL syntax to use is:
UPDATE MyEntity t SET t.dateDebut = t.dateDebut + 1 year WHERE t.id = 3
You had three errors in your query:
You referred to the name of a table instead of the name of an entity class in the UPDATE clause.
You used the unportable MySQL DATE_ADD function instead of the portable HQL date/time arithmetic described here.
The syntax of your WHERE clause was garbled.
Perhaps you meant for this to be a native SQL query, in which case you called the wrong method of Session. But there's no need to use native SQL for the above query. As you can see, HQL is perfectly capable of expressing that query.
You can use SQL directly, via createNativeQuery, or register a new function as shown in this example to call it from HQL
I am using sql query like
String query = "Select max(case when UPPER(key)='firstname' then value end) as firstNameName, , ... order by "+orderBy;
result = em.createNativeQuery(query).getResultList();
em.close();
for some reason i would have to use dynamic +orderBy . Where orderBy =firstname ASC , lastname DESC etc. Tried using .setParameter(1, orderedBy) but in this case i am not getting expected ordered results.
For avoiding sql injection threats you firstly need to remove appending parameters to your query. When you're appending parameters in your app, the atacker can hijack your sql code (with apostrophes and other means for example)
For example:
If your query is "select * from table where name="+id
The attacker can pass to the field values such as:
'John' or 1=1; ->sees all your records in this table
Or even
'John' or 1=1;Delete all from users;' -> deleting all entries from users table.
Hijacking queries can be avoided via mechanisms such as input sanitization, input whitelisting/blacklisting(removing unwanted characters from the input/ defining a list of allowed or unnalowed characters). Most modern framerowks such as JDBC/JPA/Hibernate can offer protection from this threat.
With all this stated we should take into consideration the following scenarios:
Considering sql where parameters:
JDBC for example offers prepared statements, where you define a variable in your sql, and the framework replaces it
In your case a JPA implementation(Hibernate) also has mechanisms for avoiding this threat, also via parameterized queries and positional paramaters:
via native query positional parameters:
Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");
via named parameters(jplq)
Query q = em.createQuery("SELECT count(*) FROM mytable where username = :username");
q.setParameter("username", "test");
Considering orderBy parameters:
CriteriaQuery/spring Specifications
CriteriaBuilder cb = this.entityManager
.getCriteriaBuilder();
CriteriaQuery<RESULT> criteria = cb.createQuery(RESULT.class);
Root<RESULT> root = criteria.from(RESULT.class);
return this.entityManager.createQuery(
criteria.select(root).orderBy(cb.asc(root.get("ORDER_BY_FIELD"))))
.getResultList();
More on criteriaQueries usage and config here
Passing orderBy via spring specific Sort parameter built beforehand(using the spring-data library)
Sort sort = Sort.by(Sort.Direction.ASC, "criteria");
em.createQuery(QueryUtils.applySorting(yourSqlQuery_withoutSorting,sort));
annotate method with #Query with spring-data library:
You can achieve the same result with less boiler plate code(without injecting an entityManager and creating a nativeQuery) by just annotating a method with a #Query annotation:
#Query("select u from User u where u.lastname like ?1%")
List<User> findByAndSort(String lastname, Sort sort);
Note:
Native vs non-native(jpql):
JOQL queries are independent of the database vendor(MySQL,PostGres,Oracle,DB2), nativeQueries usages are more focused when you need to use a database specific functionalities which differes accross vendors.
For a brief example jpql can not support native [With]2 clause PLSQL standard functions
Regarding your edit:
You can try to apply the following sql trick for dynamic ordering:
SELECT param1, param2 ...
FROM ...
ORDER BY case when :sortParam='name asc' then name asc END
case when :sortParam='name desc' then name desc END
....
else 0
I am absolutly new in Hibernate and I have the following problem.
I have this standard SQL query:
SELECT count(*)
FROM TID003_ANAGEDIFICIO anagraficaEdificio
INNER JOIN TID002_CANDIDATURA candidatura
ON (candidatura.PRG_PAR = anagraficaEdificio.PRG_PAR AND candidatura.PRG_CAN = anagraficaEdificio.PRG_CAN)
INNER JOIN TID001_ANAGPARTECIPA anagPartecipa ON(anagPartecipa.PRG_PAR = candidatura.PRG_PAR)
INNER JOIN anagrafiche.TPG1029_PROVNUOIST provNuovIst ON (provNuovIst.COD_PRV_NIS = anagPartecipa.COD_PRV_NIS)
WHERE anagraficaEdificio.FLG_GRA = 1 AND provNuovIst.COD_REG = "SI";
This works fine and return an integer number.
The important thing to know is that in this query the only
parameter that can change (inserted by the user in the frontend of a webappplication) is the last one (this one: provNuovIst.COD_REG = "SI").
So, the application on which I am working use Hibernate and the requirement say that I have to implement this query using Hibernate Native SQL, I have found this tutorial:
http://www.tutorialspoint.com/hibernate/hibernate_native_sql.htm
that show this example:
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();
that, from what I have understand (correct me if I am doing wrong assertion), involves the use of an Employee model class. So th prvious query first define the query (using the :param_name syntax for the parameter), then create an SQLQuery Hibernate object, add the class used for the result, set the previous parameter neam and finally obtain a List (that I think Hibernate create as something like an ArrayList) with the retrieved object.
My problem is that I simply I have to obtain an integer value (because I have a SELECT count(*), so I will obtain an integer value and not a set of rows).
So how can I correctly use the Hibernate Native SQL to implement my SQL query into my Hibernate repository class?
Use SQLQuery.uniqueResult to retrieve a single value from the query:
String sql = "SELECT count(*) ...";
SQLQuery query = session.createSQLQuery(sql);
// set parameters...
int count = ((Number)query.uniqueResult()).intValue();
I want to use spring-batch for retrieving and processing data from a postgres db.
I have a working SQL statement that would give me the full result set (about 400k entries):
private static final String QUERY = "SELECT * FROM MyDataTable ";
Now I want to use the JpaPagingItemReader so that the data is fetched (and written elsewhere) in chunks:
JpaPagingItemReader<MyEntity> reader = new JpaPagingItemReader<>();
reader.setEntityManagerFactory(emf);
reader.setQueryString(QUERY);
But it does not work:
[] 2014-09-17 16:31:58,234 ERROR : QuerySyntaxException: unexpected token: * near line 1, column 8 [SELECT * FROM my_data_table]
I also tried SELECT FROM MyDataTable and SELECT m FROM MyDataTable m without the star. Same result.
So, how can I execute that hql query with spring-batch?
By the way: the query works fine in a sql editor like pgAdmin.
SELECT m FROM MyDataTable m is almost correct (it is valid JPQL query as long as you have entity calles MyDataTable). So, it seems that you don't have entity class named MyDataTable.
As JpaPagingItemReader#setQueryString(String) accepts JPQL queries you should make sure that you have entity class for this table and then you should use its name instead MyDataTable.
By the way - for HQL queries there's HibernatePagingItemReader.
I am trying to write query with multiple select subnets in it.But I defined a nativequery
I am giving error. Compiler specifies that "(" after "from" is not proper. How can I define
a native query in JPA 2.0
For eaxmple:
SELECT *
from (SELECT ****C) REI3 where column1 != 1
GROUP BY REI3.column2 order by REI3.column3 ASC
JPA does not have too much to do with validating SQL syntax, query is passed to JDBC driver. Likely you are trying run query such a way, that it is interpreted as JP QL. Instead try following method to execute it as
Query q = em.createNativeQuery("Your SQL here");
Other alternative is to use NamedNativeQuery Example