I am trying to get total number of points back from my MySQL database using JDBC and prepared statements. I currently have
private static final String SELECT_TOTAL_POINTS_FROM_LEVEL_BY_CUSTOMER =
"select sum(points) from level_up where customer_id = ?";
#Override
public int getTotalLevelUpPointsByCustomerId(int customerId) {
int points = jdbcTemplate.queryForObject(SELECT_TOTAL_POINTS_FROM_LEVEL_BY_CUSTOMER,
Integer.class);
return points;
}
and my controller method is
#GetMapping("/points/{customerid}")
ResponseStatus(HttpStatus.OK)
public int getTotalPoints(#PathVariable("customerid") int customerId) {
return service.getTotalPoints(customerId);
}
How can i just get the points back from the database with just the customer id?
ERROR BELOW
"message": "StatementCallback; bad SQL grammar [select sum(points) from level_up where customer_id = ?]; nested exception is java.sql.SQLSyntaxErrorException: 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 '?' at line 1",
You were using a method that doesn’t allow for passing arguments. Use a method that allows for passing in arguments, like: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html#queryForObject-java.lang.String-java.lang.Object:A-int:A-java.lang.Class-
Related
This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Having a Column name as Input Parameter of a PreparedStatement
(1 answer)
Closed 1 year ago.
I am writing a student management app and have created a function to update student data-
public static void updateStudent(int id, int input) throws SQLException {
Scanner sc = new Scanner(System.in); //Scanner object
Connection connection = ConnectionSetup.CreateConnection(); //Setting up connection
String updateStatement = "UPDATE student_details SET ? = ? WHERE 's_id' = ?;"; //Initializing query
PreparedStatement pstmt = connection.prepareStatement(updateStatement);
System.out.println("Enter new name: ");
String newName = sc.nextLine();
pstmt.setString(1,"s_name"); //sets first ? to the columnname
pstmt.setString(2,newName); //sets the second ? to new name
pstmt.setString(3, String.valueOf(id)); //sets the third ? to the student ID
pstmt.execute(); //executes the query
All the other CRUD functions work fine, but this one throws the following error after inputting all the info-
Exception in thread "main" java.sql.SQLSyntaxErrorException: 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 ''s_name' = 'Prateek' WHERE 's_id' = '6'' at line 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:371)
at com.Student.manage.StudentFunc.updateStudent(StudentFunc.java:76)
at Start.main(Start.java:58)
I tried printing the finalized query and it has correct syntax and works in the MySQL Console-
SQL Query is: UPDATE student_details SET 's_name' = 'new name' WHERE 's_id' = '6';
What is the bug here? Please help me understand.
You can't use query parameters for column names (or any other identifer, or SQL keywords, etc.). When you use a query parameter, it is interpreted as a constant value. So your UPDATE statement is executed as if you had written it this way:
UPDATE student_details SET 's_name' = 'new name' WHERE 's_id' = '6';
This does not work. You can't use a string constant value as the left hand side of an assignment*. When I test it in my local MySQL client, I get this error:
ERROR 1064 (42000): 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 ''s_name' = 'new name' WHERE 's_id' = '6'' at line 1
The error reports it got confused at 's_name', because a quoted string literal is not valid at that place in an UPDATE statement.
The WHERE clause is also a problem. It's not a syntax error, but it doesn't do what you probably intended.
WHERE 's_id' = '6';
This compares the string value 's_id' to the string value '6', it does not compare the column s_id to a value. Obviously the string 's_id' is not equal to '6', so the condition will always evaluate as false, and no rows will be updated.
* You can't put a constant value on the left hand of an assignment in most other programming languages, either.
I am trying to get 3 fields from 1 table using a function and I am getting errors:
CREATE OR REPLACE FUNCTION sp_search_test_ui_test_prog_revision(dev TEXT)
RETURNS table (dev_op_test_id BIGINT, test_program_name TEXT, test_program_revision TEXT)
AS $$
BEGIN
RETURN QUERY
SELECT dev_op_test_id, test_program_name, test_program_revision
FROM dev_op_test
WHERE device = dev
ORDER BY dev_op_test_id;
END;
$$ LANGUAGE plpgsql;
The JAVA code is below: (device is a String passed to this method) Is this where the error is?
// Get unique devices from dev_op_test
String sql = " SELECT sp_search_test_ui_test_prog_revision(" + device + ") ";
PreparedStatement statement = pgConn.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
// Clear from previous run
cboTestProgDev.getItems().clear();
while (rs.next()) {
TestProgRev tpr = new TestProgRev();
tpr.setDevOpTestId(rs.getLong(1));
tpr.setTestProgramName(rs.getString(2));
tpr.setTestProgramRevision(rs.getString(3));
testProgs.add(tpr);
cboTestProgDev.getItems().add(tpr.toString());
}
And this is the error I keep getting. Notice it's telling me the column doesn't exist, which is true because that is a value not a column name. Any ideas??? I know it may be something simple, I just can't seem to ding the anwser.
The query you are sending is
SELECT sp_search_test_ui_test_prog_revision(mnf0306aa)
Do you notice the missing single quotes around the string? That is why PostgreSQL interprets it as a column name and complains that the column does not exist.
Composing queries with string concatenation is dangerous, it exposes you to the dangers of SQL injection. If device contains a single quote, your statement would cause an error or worse – a skilled attacker could do anything with your database.
Use the power of prepared statements to avoid that danger:
java.sql.PreparedStatement statement =
pgConn.prepareStatement("SELECT * FROM sp_search_test_ui_test_prog_revision(?)";
statement.setString(1, device);
java.sql.ResultSet rs = statement.executeQuery();
public List<Hero> list() throws SQLException {
return list(0, Short.MAX_VALUE);
}
public List<Hero> list(int start, int count) throws SQLException{
Connection c = this.getConnection();
QueryRunner runner = new QueryRunner();
String sql = "select * from hero order by id desc limit ?,? ";
Object params[] = {"start", "count" };
List<Hero> heros = (List<Hero>) runner.query(c,sql,new BeanListHandler(Hero.class),params);
DbUtils.closeQuietly(c);
return heros;
}
Before that I have imported Dbutils JAR that I need, like org.apache.commons.dbutils.handlers.BeanListHandler and
org.apache.commons.dbutils.QueryRunner
But after running my project, it goes wrongs whose message is :
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 ''start','count'' at line 1 Query: select * from hero order by id
desc limit ?,? Parameters: [start, count]
I know that something wrong in program, but I dont want to find all, I just want to find part of my table using limit ?.? (I only know this sql sentence can do that).
Could u please help me?
You're passing strings as your parameters, so it's running your SQL limit literally as LIMIT 'start','count'
Try this instead:
Object params[] = {start, count };
So that you're building a parameter array of your actual int values (now autoboxed to Integer)
Is there way to create sql query on the fly with MyBatis? To concretize: I have a query, where part of it (but not parameter) needs to be created in the runtime:
with dummy (id) as (
values (#{rangeEnd}) union all
select id - 1 from dummy where id - 1 >= #{rangeStart}
).......
The second part can be used as parameter, but, when trying the query as it is I get an exception:
[SQL0584] NULL or parameter marker in VALUES not allowed.
With plain JDBC I use MessageFormat:
PreparedStatement ps = connection.prepareStatement(
MessageFormat.format(MY_QUERY, currentRange.getRangeEnd()))
, but I haven't found a way how to do it with MyBatis.
It's really easy (answer from Dynamic Select SQL statements with MyBatis):
with dummy (id) as (
values (${rangeEnd}) union all
select id - 1 from dummy where id - 1 >= #{rangeStart}
).......
Use #SelectProvider annotation:
public interface SqlMapper {
static class PureSqlProvider {
public String sql(String sql) {
// Create your query here
return sql;
}
}
#SelectProvider(type = PureSqlProvider.class, method = "sql")
public List<Dummy> select(String sql);
}
I have a SQL Server Stored Procedure that looks like this:
CREATE PROCEDURE [dbo].[my_stored_procedure]
(
#num INT,
#name VARCHAR(50),
#start_date DATETIME,
#end_date DATETIME
)
AS
BEGIN
...
END
And an Entity Object with a NamedNativeQuery that looks like this:
#Entity
#NamedNativeQuery(
name = "myObject.myStoredProcedure",
query = "call my_stored_procedure(:num, :name, :start_date, :end_date)",
callable = true,
readOnly=true,
resultSetMapping="implicit"
)
#SqlResultSetMapping(
name="implicit",
entities=#EntityResult(entityClass=org.mycompany.object.MyObject.class)
)
public class MyObject implements Serializable {
...
But when I try to call it in my DAO like so:
List<MyObject> objects = (List<MyObject>) getHibernateTemplate().execute(new HibernateCallback() {
#Override
public Object doInHibernate(Session session) throws HibernateException {
return session.getNamedQuery("myObject.myStoredProcedure")
.setInteger("num", num)
.setString("name", name)
.setDate("start_date", startDate)
.setDate("end_date", endDate)
.list();
}
});
But I get this error:
12 May 2010 10:55:43,040 100833 [http-8080-Processor23] ERROR org.hibernate.util.JDBCExceptionReporter - Invalid parameter index 4.
12 May 2010 10:55:43,042 100835 [http-8080-Processor23] FATAL org.mycompany.web.controller.BasePagingController - org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query
org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query
It seems like it's expecting another parameter, like a return parameter, but I tried adding a '?' to the call and all the Hibernate documentation suggests against this.
Any help would be appreciated. Thanks
The Hibernate Documentation on calling stored procedures states:
The recommended call form is standard SQL92: { ? = call functionName(<parameters>) } or { ? = call procedureName(<parameters>) }. Native call syntax is not supported.
So the 4th line in your second snippet should probably be
query = "{ ? = call my_stored_procedure(:num, :name, :start_date, :end_date) }",
I don't know, what your procedure returns, but you might want to check the following as well.Even more Hibernate Documentation:
For Sybase or MS SQL server the
following rules apply:
The procedure must return a result
set. Note that since these servers can
return multiple result sets and update
counts, Hibernate will iterate the
results and take the first result that
is a result set as its return value.
Everything else will be discarded.
If you can enable SET NOCOUNT ON in your
procedure it will probably be more
efficient, but this is not a
requirement.