What's the source of this HQL query error? - java

public List<UserDto> getTopUsersForDaysRankedByNumberOfQuestions(Integer daysCount, Integer usersCount) {
return entityManager.createQuery(
"select new com.javamentor.qa.platform.models.dto.UserDto(" +
"user.id, " +
"user.email, " +
"user.fullName, " +
"user.imageLink, " +
"user.city, " +
"(select sum(case when rep.count is null then 0 else rep.count end) " +
"from Reputation as rep where rep.author.id = user.id)), " +
"sum(case when vote.vote = 'UP_VOTE' then 1 when vote.vote = 'DOWN_VOTE' then - 1 else 0 end) as sumVotes, " +
"count(distinct answer.id) as answerCount " +
"from User as user " +
"inner join Answer as answer on answer.id = user.id " +
"left join VoteAnswer as vote on answer.id = vote.id " +
"where answer.persistDateTime > :date " +
"and answer.isDeleted = false " +
"and user.isDeleted = false " +
"group by user.id " +
"order by answerCount desc,sumVotes desc,user.id", UserDto.class)
.setParameter("date", LocalDateTime.now().minusDays(daysCount))
.setMaxResults(usersCount)
.getResultList();
}
So I have this method which should return List of UserDto but I'm getting the erorrs. Tried to fix this whole day but I still don't understand the source of these errors
o.h.hql.internal.ast.ErrorTracker : line 1:299: unexpected token: ,
o.h.hql.internal.ast.ErrorTracker : line 1:299: unexpected token: ,
o.h.hql.internal.ast.ErrorTracker : line 1:392: expecting EOF, found ')'
o.h.hql.internal.ast.ErrorTracker : line 1:392: expecting EOF, found ')'
Is this somehow syntax related or I'm doing something completely wrong?

Try doing a simple select dto from user, and if that works add the rest of the query sentence by sentence until you find the one that throws the error.

Related

WITH Recursive query is not working when run using entityManager native query

I'm running this PostgreSQL query on Java and it is throwing an error "ERROR: syntax error at or near ":".
But the query is working on Postgresql when I run directly.
I'm thinking Array[]::integer[] is causing the issue. Can someone has any idea?
String query = "WITH RECURSIVE tree AS ( SELECT id, ARRAY[]::integer[] AS ancestors \n" +
" FROM regions \n" +
" WHERE parent_id IS NULL\n" +
" UNION ALL \n" +
" SELECT soato.id, tree.ancestors || regions.parent_id \n" +
" FROM regions, tree \n" +
" WHERE regions.parent_id = tree.id \n" +
") \n" +
" SELECT d.id FROM department d \n" +
" WHERE d.region_id IN (select id from tree where 1703 = ANY(tree.ancestors))";
Query q = entityManager.createNativeQuery(query);
q.getResultList();
Use an explicit cast to avoid the implicit PostgreSQL option :: for casting.
ARRAY[CAST(NULL AS INTEGER)] AS ancestors

Bind #param in a Jpa repository native query inside single quotations

I am looking for a way to bind a given param in a native query where the value has to be inside single quotations, like so:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - interval ':timeThreshold' HOUR " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);
However, when I try to run this, it results in hibernate not being able to bind the timeThreshold value as it is provided inside the single quotations ''.
Does anyone know how this can be resolved?
The problem you are having with your native Oracle query has to do with trying to bind a value to an interval literal. You can't do that. Instead, use the NUMTODSINTERVAL() function:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - numtodsinterval(:timeThreshold, 'hour') " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);

Spring Boot Mybatis Dynamic query

Hello im pretty new to mybatis and is the first time im trying to use with annotations in spring boot.
My code is something like this :
#Select("<script>"
+ "SELECT t.something, s.somewhat, "
+ "FROM t.table1 t "
+ "LEFT JOIN table2 s ON t.id = s.id "
+ "WHERE s.delete_date IS NULL "
+ "<if test=\"isnew\"> "
+ "AND t.insert_date = t.update_date "
+ "AND (t.score >= s.min_score AND t.score <= s.max_score) "
+ "</if>"
+ "union "
+ "ANOTHER SIMILAR QUERY WITH ANOTHER <IF> + "</script>")
List<Map<String, Object>> methodName(#Param("isnew") Boolean isNew);
This is the error.
Caused by: java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Could not find value method on SQL annotation. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 822;
Im almost sure there is an error of syntax very predictable but I cant find it.
Here are some examples of what I tried, none of them works:
"<if test="isnew = true">"
"<if test="isnew == true">"
"<if test="isnew != false">"
"<if test="isnew"> "
"<if test=#{isnew}"> "
"<if #{isnew} = true> "
Thanks in advance
For those who may have the same problem this is the solution:
You have to escape the character < , because mybatis takes it as an unopened tag, &lt will work :
+ "SELECT t.something, s.somewhat, "
+ "FROM t.table1 t "
+ "LEFT JOIN table2 s ON t.id = s.id "
+ "WHERE s.delete_date IS NULL "
+ "<if test=\"isnew\"> "
+ "AND t.insert_date = t.update_date "
+ "AND (t.score >= s.min_score AND t.score lt;= s.max_score) "
+ "</if>"
+ "union "
+ "ANOTHER SIMILAR QUERY WITH ANOTHER <IF> + "</script>")
List<Map<String, Object>> methodName(#Param("isnew") Boolean isNew);```

Problems with aggregate SQL functions in Spring Boot application

I'm working on a website in a Spring Bootwhich is connected to a MySQL db. In the db i have two tables: Player and Match and i created a query that should return me a list of players with count of matches they already played. The problem is that typed aggregate function count(M) doesn't and I don't know that I'm doing wrong. In db I have e.g. Player with id = 1 and two played Matches, another with one Match, and another with 0. What I get as a result is one Player with 3 played Matches. If i type M.id instead of count(M), I get two rows for Player 1 (one for Match id), and onw row for the second. What is wrong with my code?
#Query( "select new dto.PlayerDTO(" +
" P.id, " +
" P.nickname, " +
" count(M), " +
"from " +
" Player P left join Match M on P = M.player " +
"where " +
" P.games like %?1% ")
List<PlayerDTO> findPlayersForGame(String game);
When you count() on the joined table, you have to use group by statement:
#Query( "select new dto.PlayerDTO(" +
" P.id, " +
" P.nickname, " +
" count(M), " +
"from " +
" Player P left join Match M on P = M.player " +
"where " +
" P.games like %?1% " +
"group by P.id ")
List<PlayerDTO> findPlayersForGame(String game);

sql syntax error, but concatenated text runs fine in Datagrip

I'm trying to run a query, but I get an error when running it.
However, I'm using Intellij and when I use the copy string concatenation to clipboard feature, and run the query in the datagrip, the query runs fine (after putting in the parameters)
The error I am getting is "ERROR: syntax error at or near "tstoredarticle"\n Position: 199"
I find it a bit weird that it's showing there's a line change, after tstoredartiacle but besides that I don't see what's wrong.
What could be some issues that could cause a problem like that?
my query in intellij looks like this:
private ResultSet getHuaweiSqlQuery(Integer intBrandID, Integer intStorageID, Vector<Integer> vecArticleTypes, int iCurrencyID, int iContactSupplierID, int secondaryStorage, BigDecimal exchangeRate) throws SQLException {
return Hibernate3To4Utils.getConnection(session).createStatement().executeQuery("SELECT storedarticleid, "
+ " CASE WHEN storedarticle_storageid = " + intStorageID
+ " THEN id_storedarticleid_replacement ELSE"
+ " (SELECT COALESCE(id_storedarticleid_replacement, storedarticleid)"
+ " FROM etel.tstoredarticle x"
+ " WHERE tstoredarticle.storedarticle_articleid = x.storedarticle_articleid"
+ " AND x.storedarticle_storageid = " + intStorageID + ")"
+ " END as id_storedarticleid_replacement,"
+ " articlename,"
+ " articledescription, CASE WHEN price IS NULL THEN last_innprice*" + exchangeRate
+ " ELSE price END as last_innprice, id_modelids[1] as order_modelid, storedarticleamount-amount_in_order-amount_waiting as disponibelt,"
+ " amount_in_order, amount_in_bestilling, sum(tusedarticle.amount) as ant_artikler, articleid,amount_waiting, location"
+ " FROM etel.tstoredarticle"
+ " INNER JOIN etel.tarticle as b ON storedarticle_articleid = b.articleid"
+ " LEFT JOIN etel.tusedarticle ON usedarticle_storedarticleid = storedarticleid"
+ " AND ((tusedarticle.datesnap >= CAST(now() as date)-" + LOOK_BACK_DAYS
+ " AND usedarticlefromstorage = true) OR waiting = true)"
+ " LEFT JOIN etel.torder ON usedarticle_orderid = orderid AND torder.id_serviceplaceid = " + Constants.SERVICEPLACE
+ " LEFT JOIN etel.tsupplier_price ON id_articleid = b.articleid"
+ " AND tsupplier_price.id_serviceplaceid = " + Constants.SERVICEPLACE
+ " AND tsupplier_price.id_currencyid = " + iCurrencyID
+ " AND tsupplier_price.id_contactid_supplier = " + iContactSupplierID
+ " LEFT JOIN etel.tusedarticle as last_used on storedarticleid = last_used.usedarticle_storedarticleid"
+ " AND last_used.usedarticleid = (select MAX(latest_usedarticle.usedarticleid) from etel.tusedarticle as latest_usedarticle where"
+ " latest_usedarticle.usedarticle_storedarticleid = storedarticleid)"
+ " WHERE storedarticle_storageid IN(" + intStorageID + ", " + secondaryStorage + ") AND b.id_brandid = " + intBrandID
+ " AND id_articletypeid IN (" + getStringFromArray(vecArticleTypes.toArray()) + ")"
+ " AND tstoredarticle.passive <> true"
+ " GROUP BY storedarticleid,id_storedarticleid_replacement, articlename, articledescription, last_innprice, id_modelids[1],"
+ " storedarticleamount, amount_in_order, amount_in_bestilling, articleid,price,amount_waiting, location, last_used.datesnap"
+ " ORDER BY id_storedarticleid_replacement, storedarticleid");
}
and here's the same query after using the copy string concatenation to clipboard feature:
(this runs fine)
SELECT storedarticleid,
CASE WHEN storedarticle_storageid = ?
THEN id_storedarticleid_replacement ELSE
(SELECT COALESCE(id_storedarticleid_replacement, storedarticleid)
FROM etel.tstoredarticle x
WHERE tstoredarticle.storedarticle_articleid = x.storedarticle_articleid
AND x.storedarticle_storageid = ?)
END as id_storedarticleid_replacement,
articlename,
articledescription, CASE WHEN price IS NULL THEN last_innprice*?
ELSE price END as last_innprice, id_modelids[1] as order_modelid, storedarticleamount-amount_in_order-amount_waiting as disponibelt,
amount_in_order, amount_in_bestilling, sum(tusedarticle.amount) as ant_artikler, articleid,amount_waiting, location
FROM etel.tstoredarticle
INNER JOIN etel.tarticle as b ON storedarticle_articleid = b.articleid
LEFT JOIN etel.tusedarticle ON usedarticle_storedarticleid = storedarticleid
AND ((tusedarticle.datesnap >= CAST(now() as date)-42
AND usedarticlefromstorage = true) OR waiting = true)
LEFT JOIN etel.torder ON usedarticle_orderid = orderid AND torder.id_serviceplaceid = ?
LEFT JOIN etel.tsupplier_price ON id_articleid = b.articleid
AND tsupplier_price.id_serviceplaceid = ?
AND tsupplier_price.id_currencyid = ?
AND tsupplier_price.id_contactid_supplier = ?
LEFT JOIN etel.tusedarticle as last_used on storedarticleid = last_used.usedarticle_storedarticleid
AND last_used.usedarticleid = (select MAX(latest_usedarticle.usedarticleid) from etel.tusedarticle as latest_usedarticle where
latest_usedarticle.usedarticle_storedarticleid = storedarticleid)
WHERE storedarticle_storageid IN(?, ?) AND b.id_brandid = ?
AND id_articletypeid IN (?)
AND tstoredarticle.passive <> true
GROUP BY storedarticleid,id_storedarticleid_replacement, articlename, articledescription, last_innprice, id_modelids[1],
storedarticleamount, amount_in_order, amount_in_bestilling, articleid,price,amount_waiting, location, last_used.datesnap
ORDER BY id_storedarticleid_replacement, storedarticleid
Don't use string concatenation with dynamic text values to build a SQL statement.
For one, if the text values are supplied by a user, you're leaving yourself vulnerable to SQL injection attacks, allowing hackers to steal your data and delete your tables.
But you also have problems getting the text values quoted and escaped correctly.
Instead, use a PreparedStatement, where you place ? markers anywhere a dynamic value needs to go. That is the string in the clipboard.
Example: You're doing:
String name = "John";
String sql = "SELECT * FROM Person WHERE name = " + name;
That gives you this text at runtime:
SELECT * FROM Person WHERE name = John
which is wrong, because the text value needs to be quoted:
SELECT * FROM Person WHERE name = 'John'
You could try
String name = "John's Cross";
String sql = "SELECT * FROM Person WHERE name = '" + name + "'";
but that's also wrong, because this new text value has embedded quotes and would produce:
SELECT * FROM Person WHERE name = 'John's Cross'
To get it right, use a PreparedStatement:
String name = "John's Cross";
String sql = "SELECT * FROM Person WHERE name = ?";
PreparedStatement stmt = Hibernate3To4Utils.getConnection(session).prepareStatement(sql);
stmt.setParameter(1, name);
return stmt.executeQuery();
The JDBC driver will take care of any escaping needed, and thereby protects you from both SQL injection attacks and SQL syntax errors.

Categories

Resources