Java Spring JDBC template problem - java

public List<Weather> getWeather(int cityId, int days) {
logger.info("days: " + days);
return getSimpleJdbcTemplate().query("SELECT weather.id, cities.name, weather.date, weather.degree " +
"FROM weather JOIN cities ON weather.city_id = cities.id " +
"WHERE weather.city_id = ? AND weather.date BETWEEN now()::date AND (now() + '? days')::date",
this.w_mapper, cityId, days);
}
error :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [SELECT weather.id, cities.name, weather.date, weather.degree FROM weather JOIN cities ON weather.city_id = cities.id WHERE weather.city_id = ? AND weather.date BETWEEN now()::date AND (now() + '? days')::date]; The column index is out of range: 2, number of columns: 1.; nested exception is org.postgresql.util.PSQLException: The column index is out of range: 2, number of columns: 1.
it works with :
public List<Weather> getWeather(int cityId, int days) {
logger.info("days: " + days);
return getSimpleJdbcTemplate().query("SELECT weather.id, cities.name, weather.date, weather.degree " +
"FROM weather JOIN cities ON weather.city_id = cities.id " +
"WHERE weather.city_id = ? AND weather.date = now()::date",
this.w_mapper, cityId);
}
so the problem is when im using two ? marks in my query.
how can i make it work to with 2 ? marks???

The problem is probably in this part:
'? days'
The question mark is inside a literal string and so it is not recognized by the sql parser. You could try to rewrite it using the string concatenation operator, although I'm not 100% sure that is valid syntax in this case.
According to this page on the postgres wiki you should be able to simply omit the string 'days', since adding a date and an integer is interpreted as adding the specified number of days.
BETWEEN now()::date AND now()::date + ?

Rewrite the SQL part
AND weather.date BETWEEN now()::date AND (now() + '? days')::date
as
AND weather.date BETWEEN now()::date AND ?
and set it with a fullworthy java.sql.Date value instead of days.
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, days);
Date endDate = new Date(calendar.getTimeInMillis());
// ...
(once again, it's java.sql.Date, not java.util.Date!)

The error is saying that you only have 1 param (ie a ?) in the first sql statement, but you are passing in two args. Spring doesn't know what to do with the second arg.

Related

Bad SQL grammar, Oracle : while the query is working fine in DB editor in Spring Boot Application

I am using Oracle DB with Spring Boot Application. The query is working fine in DBeaver but not in actual application. I have copied the query from the console error message.
Query calling function:
public List<UserFullNameDesignationDto> getUserFullNameDesignation(String[] userNames) {
String queryParam = "";
for (String uName : userNames) {
queryParam += "'" + uName + "',";
}
queryParam = queryParam.substring(0, queryParam.length() - 1);
String sql =
"SELECT\n"
+ "\tu.USERNAME,\n"
+ "\tu.FULL_NAME,\n"
+ "\tcd.NAME \n"
+ "FROM\n"
+ "\tUSER_ENTITY u\n"
+ "LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID \n"
+ "WHERE\n"
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
var rowMapper = BeanPropertyRowMapper.newInstance(UserFullNameDesignationDto.class);
List<UserFullNameDesignationDto> list = jdbcTemplate.query(sql, rowMapper);
System.out.println(list);
return jdbcTemplate.query(sql, rowMapper);
}
Stack trace:
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [SELECT
u.USERNAME,
u.FULL_NAME,
cd.NAME
FROM
USER_ENTITY u
LEFT JOIN CORE_DESIGNATIONS cd ON u.DESIGNATION_ID = cd.ID
WHERE
u.USERNAME IN ('aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1');
]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
............
Caused by: java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
This line will be
'aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1'
replaced by variable.
The root cause of the error is that you copied the semicolon in the JDBCTemplate statement (which works in SQL IDE but not in JDBC)
+ ");\n";
remove it
+ ")\n";
and it will work (or you get an other error;)
Anyway you should re-think your way of concatenation input in the SQL statement towards the usage of bind variables. There are lot of examples for binding IN list on this site.
As far as I can tell, you'll have to split values stored in that variable into rows. How? Like this:
SQL> with test(queryParam) as
2 (select q'['aro_user','afo_user1','afo_user1','afo_user1','afo_user1','afo_user1']' from dual)
3 select regexp_substr(queryParam, '[^,]+', 1, level) val
4 from test
5 connect by level <= regexp_count(queryParam, ',') + 1
6 /
VAL
----------------------------------------------------------------------
'aro_user'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
'afo_user1'
6 rows selected.
SQL>
It means that this:
+ "\tu.USERNAME IN ("
+ queryParam
+ ");\n";
should be modified so that queryParam is replaced by
( SELECT REGEXP_SUBSTR (queryParam,
'[^,]+',
1,
LEVEL) val
FROM test
CONNECT BY LEVEL <= REGEXP_COUNT (queryParam, ',') + 1)
List<String> userIds = Arrays.asList("User1", "User2");
String inSql = String.join(",", Collections.nCopies(userIds.size(), "?"));
List<User> employees = jdbcTemplate.query(String.format("SELECT * FROM Users WHERE id IN (%s)", inSql), userIds.toArray());
Please see, https://www.baeldung.com/spring-jdbctemplate-in-list for

JPA Repository : Cannot bind parameter for timezone

I have the following code in JPA repository and it works.
#Query(
value =
"SELECT EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone 'Asia/Seoul') AS hour,\n"
+ " COUNT(STO.id) AS count, SUM(STO.grandtotalprice) AS sum, AVG(STO.grandtotalprice) AS average\n"
+ "FROM store.storeorder AS STO\n"
+ "WHERE STO.store_id=?1 AND STO.createddate >= ?2 AND STO.createddate < ?3 AND STO.orderstatus IN ('CLOSED')\n"
+ "GROUP BY EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone 'Asia/Seoul') \n"
+ "ORDER BY hour ASC;",
nativeQuery = true)
List<ReportHourly> hourlyReport(
UUID storeId, LocalDateTime from, LocalDateTime to);
However, when I try to input timezone as parameter like below, it fails with saying
org.postgresql.util.PSQLException: ERROR: column "createddate" must appear in the GROUP BY clause or be used in an aggregate function
#Query(
value =
"SELECT EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone ?4) AS hour,\n"
+ " COUNT(STO.id) AS count, SUM(STO.grandtotalprice) AS sum, AVG(STO.grandtotalprice) AS average\n"
+ "FROM store.storeorder AS STO\n"
+ "WHERE STO.store_id=?1 AND STO.createddate >= ?2 AND STO.createddate < ?3 AND STO.orderstatus IN ('CLOSED')\n"
+ "GROUP BY EXTRACT(HOUR FROM STO.createddate\\:\\:timestamptz at time zone ?4) \n"
+ "ORDER BY hour ASC;",
nativeQuery = true)
List<ReportHourly> hourlyReport(
UUID storeId, LocalDateTime from, LocalDateTime to, String timeZone);
I am not sure why parameterization doesn't work for this case.
I think the problem here is that JDBC doesn't really know about indexed bind arguments, it only knows about ? for binding.
This means the two occurrences fo ?4 get translated into two different bind parameters and therefore Postgres sees an expression in the select clause that is not part of the GROUP BY nor an aggregate function.
Since by construction the two actually are the same you should be fine wrapping the expression for hour in MAX(...) or any other aggregate function that returns the argument value when applied to a single row.

Resultset throws syntax error when there are no records in database

Below I show my sql query which is dynamic in Java.
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -365);
Adjust to 12 months before current month with 0 hrs and min
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 1, 0, 0, 0);
String lastYearTime = String.valueOf(cal.getTimeInMillis() / 1000);
while(iterator.hasNext())
{
tablename = Database.getTableName((String)iterator.next());
fields = "status,count(*) as count";
query.append("select " + fields + " from " + tablename + " where");
query.append(" toid ='" + collegeId + "'");
query.append(" and dtstamp >='" + lastYearTime + "'");
query.append(" group by status");
if(i.hasNext())
query.append(" UNION ");
}
StringBuffer countquery = new StringBuffer("select status, SUM(count) as count from ( " + query + ")as temp group by status ");
ResultSet rs = Database.executeQuery(countquery.toString(), connection);
In the above query, tablename will be random based on other factors. collegeId can be any id. Status can be like dropout,pursuing or any random status.
When I execute my above query, result set works fine and data is displayed. But when there are no records in the database then it throws a sql syntax error 1064 stating
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')as temp group by status' at line 1
Problem1
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')as temp group by status' at line 1
You have a problem in your query:
select status, SUM(count) as count from ( " + query + ")as temp group by status
You should to make a space in your query here :
from ( " + query + ")as
replace this ")as with this ") as
EDIT
Problem2
SQL Exception : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') as temp group by status' at line 1 SQL State : 42000 Error Code : 1064
Your query is a String so you should to put it between two 'query'
now replace this :
select status, SUM(count) as count from ( " + query + ")as temp group by status
By this :
select status, SUM(count) as count from ( '" + query + "') as temp group by status
Good luck.
Resultset throws syntax error when there are no records in database
No it doesn't. It throws a syntax-error exception when you have a syntax error in your query.

Java Prepared statement Sql query error

I am trying to run the following statement in a java program.My problem is the first question mark(parameter) in the statement is failing and the error message reads :
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near ''hello' ON SCHEDULE EVERY 1 WEEK STARTS CONCAT(CURRENT_DATE +
INTERVAL 1 - WEEKD' at line 1.
Is there something im missing can i not carry out a statement in this fashion ?
The query worked before i tried to add the first parameter and just added a name manually into the query ,Any help will of course be appreciated.
PreparedStatement ps1 = null;
ps1 = connection.prepareStatement("CREATE EVENT ? ON SCHEDULE EVERY 1 WEEK STARTS CONCAT(CURRENT_DATE + INTERVAL ? - WEEKDAY(CURRENT_DATE) DAY, ? ) "
+ " DO UPDATE tablename SET status = ? WHERE name= ? AND address= ?");
This is because the name hello get quoted since is passed as a parameter, in this case you could remove the parameter and just concatenate the string or just embed into the string :
connection.prepareStatement("CREATE EVENT hello ON SCHEDULE EVERY 1 WEEK STARTS CONCAT(CURRENT_DATE + INTERVAL ? - WEEKDAY(CURRENT_DATE) DAY, ? ) "
+ " DO UPDATE tablename SET status = ? WHERE name= ? AND address= ?");
or going with String format :
connection.prepareStatement(String.format("CREATE EVENT %s ON SCHEDULE EVERY 1 WEEK STARTS CONCAT(CURRENT_DATE + INTERVAL ? - WEEKDAY(CURRENT_DATE) DAY, ? ) "
+ " DO UPDATE tablename SET status = ? WHERE name= ? AND address= ?", hello));

How to embeded Datetime into SQL String

I have a need to use Statement.executeUpdate() to insert data into Database.
So every parameter must be embeded into a SQL string.
In Database, the type of two columns are datetime: Date1 and Date2
At client side, if I use following statement:
String SQLString = "INSERT INTO Position (" +
......
"Date1, " +
......
"Date2) " +
"VALUES(" +
......
//"2012-05-29 16:28:58.555" + ", " + // runtime error, always say error at 16
//"2012-05-29" + ", " + // no runtime error, but lost time and result date is also not correct
//"10-06-02" + ", " + // no runtime error, but it adds 2 days beginning at 1900-01-01 00:00:00.000
......
null
")";
Can anyone tell me how to correctly embedded Datetime into SQL String?
You should use a PreparedStatement and pass the date field ad Date ...
String SQLString = "INSERT INTO Position (Date1) VALUES (?)";
PreparedStatement prest = con.prepareStatement(SQLString);
prest.setDate(1,new Date());
prest.executeUpdate()
First up, you have to use PreparedStatement. Then you could do something like:
statement.setDate(2, new Date());

Categories