what is the problem with mysql senteceses from java? [duplicate] - java

I am using Java 11 JDBC and MySQL Connector/J 8 jar. All other CRUDs are running OK, but when I am trying to run SET foreign_key_checks = 0 or SET foreign_key_checks = 1, it shows syntax error with SQLState: 42000 and VendorError: 1064. So if there is any way to run such queries using JDBC?
try {
Statement checks = connection.createStatement();
checks.execute("set foreign_key_checks=0");
checks.close();
String tableName = json.getString("table");
RowOperation rowOperation = RowOperation.valueOf(json.getString("activity"));
JSONArray rows = json.getJSONArray("rows");
for (Object obj : rows) {
JSONObject row = (JSONObject) obj;
List<String> keys = new ArrayList<>(row.keySet());
StringBuilder sb = new StringBuilder();
String columns = keys.stream().collect(Collectors.joining(",")) + ",rowOperation,rowCreatedOn";
String questionMakrs = keys.stream().map(x -> "?").collect(Collectors.joining(",")) + ",?,?";
String query = "insert into " + tableName + " (" + columns + ") values (" + questionMakrs + "); SET FOREIGN_KEY_CHECKS=0";
PreparedStatement stmt = connection.prepareStatement(query);
int i = 0;
for (i = 0; i < keys.size(); i++) {
String key = keys.get(i);
stmt.setString(i + 1, String.valueOf(row.get(key)));
}
stmt.setString(i + 1, rowOperation.name());
i++;
stmt.setTimestamp(i + 1, Timestamp.valueOf(LocalDateTime.now()));
stmt.execute();
stmt.close();
}
} finally {
Statement checks = connection.createStatement();
checks.execute("set foreign_key_checks=1");
checks.close();
}

You are trying to execute two statements, an INSERT followed by a SET, separated by a semicolon, in a single call to prepareStatement().
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
SQL syntax for prepared statements does not support multi-statements (that is, multiple statements within a single string separated by ; characters).
You must execute the SET statement in a separate statement.

Related

Varying content of an SQL update statement in java

I need to write an update function where its content is different based on what parameters are passed, e.g. if I have updateBook(int id, String title, String author, int pages), I have to do something like:
String sql;
if((!title.equals("null"))&&(!author.equals("null"))&&(pages>0)))
sql = "UPDATE book SET title='"+title+"', author='"+author+"', pages="+pages;
else if(((!title.equals("null"))&&(!author.equals("null")))
sql = "UPDATE book SET title='"+title+"', author='"+author+"'";
else if(((!title.equals("null"))&&(pages>0)))
sql = "UPDATE book SET title='"+title+"', pages="+pages;
... //and so on
sql = sql + " WHERE bookid="+id+";";
The more fields I have in my table, the more checks I have to do, which is uncomfortable, and requires me to write a lot of code.
Also, doing something like:
sql = "UPDATE book SET ";
if(!title.equals("null"))
sql = sql +"title='"+title+"',";
if(!author.equals("null"))
sql = sql+"author='"+author+"',";
if(pages>0)
sql = sql+"pages="+pages";
sql = sql + ";";
can't work since the unwanted commas cause statement errors.
You can see as well that if I have something like 6, 7, 8 etc field the checks start to get too many, and I can't also do more separated update statements as if something goes wrong I would need to rollback any query that has been done in that function.
Is there any way round to get a custom update statement having to write few code?
Firstly, use a PreparedStatement.
I would do it something like the following.
List<Object> params = new ArrayList<>();
StringBuilder sql = new StringBuilder();
if(!title.equals("null")) {
sql.append("title = ?");
params.add(title);
}
if(!author.equals("null")) {
if (sql.length() > 0) {
sql.append(", ");
}
sql.append("author = ?");
params.add(author);
}
if(pages>0) {
if (sql.length() > 0) {
sql.append(", ");
}
sql.append("pages = ?");
params.add(pages);
}
if (sql.length() > 0) {
sql.insert(0, "UPDATE book SET ");
sql.append(" WHERE bookid=?");
java.sql.Connection conn = // however you obtain it
java.sql.PreparedStatement ps = conn.prepareStatement(sql.toString());
for (int i = 0; i < params.size(); i++) {
ps.setObject(i + 1, params.get(i));
}
ps.executeUpdate();
}

How to pass ArrayList<> as IN clause in SQL query in MySQL [duplicate]

This question already has an answer here:
Passing an Array to a SQL query using Java's PreparedStatement
(1 answer)
Closed 7 years ago.
I am using mySQL JDBC driver in my java program. I want to pass a ArrayList in the IN clause in my SQL query.
i did use a prepared statement like this, but this throws an
"java.sql.SQLFeatureNotSupportedException"exception
since mysql doesn't support this.
ArrayList<String> list = new ArrayList<String>();
PreparedStatement pstmt =
conn.prepareStatement("select * from employee where id in (?)");
Array array = conn.createArrayOf("VARCHAR", list.toArray());
pstmt.setArray(1, array);
ResultSet rs = pstmt.executeQuery();
Is there any other way to do this ? Maybe with Statement stmt.
Build the SQL statement with the correct number of markers, and set all the values.
Beware: Databases have a limit to the number of parameters allowed, though it's very high for MySQL (65535).
char[] markers = new char[list.size() * 2 - 1];
for (int i = 0; i < markers.length; i++)
markers[i] = (i & 1 == 0 ? '?' : ',');
String sql = "select * from employee where id in (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int idx = 1;
for (String value : list)
stmt.setString(idx++, value);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
// code here
}
}
}

Prepared Statement setString adding unnecessary single quotes to String

Background
I am trying to set the contents of an ArrayList into an IN clause in a Db2 SQL statement. I am using the PreparedStatement to build my query. This is our coding standard.
What I tried #1
I researched a couple ways to achieve this. I first tried using the setArray() as show in this question: How to use an arraylist as a prepared statement parameter The result was I was getting a error of Err com.ibm.db2.jcc.am.SqlFeatureNotSupportedException: [jcc][t4][10344][11773][3.65.110] Data type ARRAY is not supported on the target server. ERRORCODE=-4450, SQLSTATE=0A502 After this roadblock, I moved on to #2
What I tried #2
I then tried using the Apache Commons StringUtils to convert the ArrayList into a comma separated String like I needed for my IN clause. The result is that this did exactly what I needed, I have a single String with all my results separated by a comma.
The problem:
The setString() method is adding single quotes to the beginning and end of my String. I have used this many times, and it has never done this. Does anyone know if there is a way around this, or an alternative using the PreparedStatement?? If I use String concatenation my query works.
Code (explained above):
List<String> selectedStatuses = new ArrayList<String>(); //Used to store contents of scoped var
//Get Contents of Checkbox which are in the form of a List
selectedStatuses = (List) viewScope.get("selectedStatuses");
String selectedStatusesString = StringUtils.join(selectedStatuses, ",");
.... WHERE ATM_DET_ATM_STAT IN (?)";
ps.setString(1, selectedStatusesString);
Log Value showing correct value of String
DEBUG: selectedStatusesString: 'OPEN','CLOSED','WOUNDED','IN PROGRESS'
Visual of incorrect result
The quotes at the beginning and end are the problem.
For an IN clause to work, you need as many markers as you have values:
String sql = "SELECT * FROM MyTable WHERE Stat IN (?,?,?,?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "OPEN");
stmt.setString(2, "CLOSED");
stmt.setString(3, "WOUNDED");
stmt.setString(4, "IN PROGRESS");
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Since you have a dynamic list of values, you need to do this:
List<String> stats = Arrays.asList("OPEN", "CLOSED", "WOUNDED", "IN PROGRESS");
String markers = StringUtils.repeat(",?", stats.size()).substring(1);
String sql = "SELECT * FROM MyTable WHERE Stat IN (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < stats.size(); i++)
stmt.setString(i + 1, stats.get(i));
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Starting with Java 11, StringUtils is no longer needed:
String markers = ",?".repeat(stats.size()).substring(1);
Use two apostrophes '' to get a single apostrophe on DB2, according to the DB2 Survival Guide. Then call .setString().
To anyone else experiencing the issue with single quotes, I had to modify my function so that it doesn't use ? to set the value; instead, I just treat the entire query as a string:
public static void runQuery(String tableName, String columnName, int value, String whereName, String whereValue) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + " = " + value + " WHERE " + whereName + " = " + "'" + whereValue + "'")) {
ps.executeUpdate();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
Hope this helps

Error: Incorrect syntax near (database name)

hi I am getting this error in my Java program. Here is my query. It is working good in SQL server. but getting
Error: Incorrect syntax near 'WebApp'.
private static final String SERVICES =
"SELECT s.Service_ID "
+ ",s.[Location_ID] "
+ ",COALESCE(st.[Service_Type_Name],s.[Service_Name]) AS Service_name "
+ ",st.Service_Type_Name "
+ " FROM [WebApp].[dbo].[Services] s join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type=st.Service_Type_ID "
+ " join WebApp.dbo.Locations l on s.Location_ID=l.Location_ID "
+ " where s.Deleted=0 "
+ " ORDER BY Location_ID ";
and here is my method it is working fine on ms sql server 2008
public List<MAServiceVO> getAddServices() throws CoopCRSAPIException {
ArrayList<MAServiceVO> results = new ArrayList<MAServiceVO>();
MAServiceVO maServiceVO = null;
log.debug("==========IN VendorDAOimpl.java (service)===========");
//int serviceID = 0;
//int prevServiceID = 0;
try {
conn = MSSQLDAOFactory.createConnection();
stmt = conn.prepareStatement(SERVICES);
// stmt.setTimestamp(1, startDate);
// stmt.setTimestamp(2, endDate);
stmt.execute();
rs = stmt.getResultSet();
while (rs.next()) {
// create new service
maServiceVO = new MAServiceVO();
// set service fields
maServiceVO.setServiceID(rs.getInt("Service_ID"));
maServiceVO.setLocationID(rs.getInt("Location_ID"));
maServiceVO.setServiceName(rs.getString("Service_Name"));
maServiceVO.setServiceType(rs.getString("Service_Type_Name"));
log.debug("==========done with VendorDAOimpl.java (service)===========");
}
} catch (SQLException e) {
log.debug(e.getMessage());
throw new CoopCRSAPIException(e.getMessage(), " VendorDAOimpl", "getAddServices", 500);
} finally {
closeConnections("getAddServices");
}
log.debug("&&&&&&&&&&&&&&&&&&&&&");
log.debug("==========finsh===========");
return results;
}
I don't see anything out of whack there. If there a reason you don't have this in a stored procedure instead of pass through sql? I did notice you didn't put square brackets around your final join but that shouldn't make any difference.
Here is your query after stripping off all the extra string parts for java.
SELECT s.Service_ID
, s.[Location_ID]
, COALESCE(st.[Service_Type_Name], s.[Service_Name]) AS Service_name
, st.Service_Type_Name
FROM [WebApp].[dbo].[Services] s
join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type = st.Service_Type_ID
join [WebApp].[dbo].[Locations] l on s.Location_ID = l.Location_ID
where s.Deleted = 0
ORDER BY Location_ID;

Building a String parameter (with SQL content) from resource file for SQL PreparedStatement

I need to execute a SQL PreparedStatement in Java using jdbc.
I'm facing problems with one of the parameters because it has SQL content and also Strings from a resource file.
It looks something like this:
Required SQL:
SELECT * FROM Table T WHERE T.value = 10 AND T.display IN ('Sample1', 'Sample2')
In the above query, the Sample1 and Sample2 values must be passed through a parameter to a PreparedStatement.
PreparedStatement:
SELECT * FROM Table T WHERE T.value = 10 ?
In my application code I'm setting the parameters like:
statement.setString(1, "AND T.display IN ('Sample1', 'Sample2')");
However this is not returning the appropriate results.
Is there a better way to build this particular parameter considering it has SQL content and Strings too?
EDIT:
Sample1, Sample2 etc. are strings that are retrieved from an external file at run-time and there can be different number of these strings each time. I.e. there can be only one string Sample1 or multiple strings Sample1, Sample2, Sample3, etc..
EDIT2:
Database being used is Oracle.
The ? placeholder can only be used in a position where a value is expected in the query. Having a ? in any other position (as in your question: WHERE T.value = 10 ?) is simply a syntax error.
In other words: it is not possible to parametrize part of the query itself as you are trying to do; you can only parametrize values. If you need to add a dynamic number of parameters, you will need to construct the query dynamically by adding the required number of parameters and using setString(). For example:
StringBuilder sb = new StringBuilder(
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?");
// Note: intentionally starting at 1, first parameter already above
// Assuming always at least 1 parameter
while (int i = 1; i < params.length; i++) {
sb.append(", ?");
}
sb.append(')');
try (
PreparedStatement pstmt = con.prepareStatement(sb.toString())
) {
for (int i = 0; i < params.length; i++) {
pstmt.setString(i + 1, params[i]);
}
try (
ResultSet rs = pstmt.executeQuery();
) {
// Use resultset
}
}
Use this as PreparedStatement
"SELECT * FROM Table T WHERE T.value = 10 AND T.display IN (?, ?);"
and then call
statement.setString(1, "Sample1");
statement.setString(2, "Sample2");
before executing the statement.
Update:
String generateParamString(int params) {
StringBuilder sb = new StringBuilder("(");
for (int i = 1; i < params; i++) {
sb.append("?, ");
}
sb.append("?)");
return sb.toString();
}
List<String> samples = ... // your list with samples.
String stmtString = "SELECT * FROM Table T WHERE T.value = 10 AND T.display IN "
+ generateParamString(samples.size());
// generate statement with stmtString
for (int i = 0; i < samples.size(); i++) {
statement.setString(i + 1, samples.get(i));
}
// execute statement...

Categories