Suppose that I have a query, something like SELECT * FROM my_table where name = 'Debbie O'Brian'. As you may know in SQL Server we just need to put another ' to make it ignore single quotes. Here is what I like to do automatically.
Briefly, I need to replace all occurrences of ' with '' between two enclosing '.
Here is what I have so far:
String text = "SELECT * FROM my_table where name = 'Debbie O'Brian'";
String[] splitArray = text.split(" '");
for (int i = 0; i < splitArray.length; i++) {
String str = splitArray[i];
if (str.endsWith("'"))
str = str + " ";
// replace all single quotes
str = str.replace("'", "''");
// revert last replacement
str = str.replace("'' ", "' ");
splitArray[i] = str;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < splitArray.length; i++) {
builder.append(splitArray[i]).append(" '");
}
System.out.println(builder.substring(0, builder.length() - 2).toString());
The problem is that I am relying on existence of a white space before starting '. My question is that how can I do this without this pre-assumption?
Any help (even suggestion of an algorithm) is much appreciated. Please mention that there might be more than one single quoted string in query.
EDIT: I am using Hibernate to execute native SQL and getting the whole SQL query as input.
The best way to handle single quotes and other special characters in an SQL query is by using Parametrized Queries. It is also more secure. I would recommend doing a search on 'SQL Injection'. That will teach you how to protect against and handle the single quotes in your query.
If you use JDBC use
PreparedStatement ps = conn.prepareStatement("SELECT * FROM my_table where name = ?")
ps.setString(1, name);
As you are using Hibernate, similar to what #B.O.B said use parameterised queries:
String queryString = "SELECT * FROM my_table where name = :name";
Query query = getSession().createSQLQuery(queryString);
query.setString("name", name);
OK, as I mentioned above, my problem was not SQL injection. What I was after, at this point seems to be impossible unless I implement a SQL parser which is obviously too much for the requirement. So I am going to stick with my pre-assumption and give up trying to fix the wrong input as two people mentioned in comments.
Thank everybody for your answers.
Related
Cursor cursor = database.rawQuery
("SELECT * FROM table where word like '?%'".replace("?",
letter),null);
When there is a single quote in string letter app crashes.
Need to solve without letter.replace(" ' ", " ") because there are words in table with quotes in it.
You are using the statement API incorrectly. You should bind the literal string value you want to appear in the actual query. That is, do this:
String param = letter + "%";
String query = "SELECT * FROM table WHERE word LIKE ?";
Cursor cursor = database.rawQuery(query, new String[] { param });
It is the API's responsibility to correctly escape the LIKE expression you are trying to build.
I am trying to read a temporary variable created from my MySql query as follows:
String name = "";
selectQuery = "select (select "
+ "CONCAT(s.firstname,\" \",s.surname) "
+ "AS name) "
+ "from student s, marks m where m.grade = 'fail'";
try{
pstmt = con.prepareStatement(selectQuery);
rs = pstmt.executeQuery(selectQuery);
int count = 0;
while(rs.next()){
name = rs.getString("name");
System.out.println(++count+". "+name);
}
rs.close();
pstmt.close();
}catch(Exception e){
e.printStackTrace();
}
I get SQLException as column 'name' not found. When I run the query in MySql server it runs fine.
In order for the alias to apply, it must be places outside the nested query's parenthesis, not inside it. However, you could just drop it altogether and just use the concat call directly in the select list.
Two more side notes:
Implicit joins (i.e., placing more than one table in the from list) have been deprecated for quite a while. It's considered a better practice to use explicit joins.
Regardless of the joining syntax you're using, you're missing the join condition.
Using concat_ws instead of concat may save you some hassle with handling the white space yourself.
To make a long story short:
select CONCAT_WS(' ', s.firstname, s.surname) AS name
FROM student s
JOIN marks m ON s.id = m.student_id
WHERE m.grade = 'fail'
I want to filter my table to show records by month so i make a textboxes for the user input. Now i dont know if my query is correct. I dont have any error but also doesnt have any results. I use LIKE because i dont have specific day provided. Can someone suggest a better way?
ConnectToDatabase conn = null;
conn = ConnectToDatabase.getConnectionToDatabase();
String query = "Select * from inventoryreport where InDate LIKE "+txtYear.getText()+""+ txtMonth.getText()+"";
conn.setPreparedStatement(conn.getConnection().prepareStatement(query));
conn.setResultSet(conn.getPreparedStatement().executeQuery());
java.sql.ResultSetMetaData metaData = conn.getResultSet().getMetaData();
int columns = metaData.getColumnCount();
for (int i = 1; i <= columns; i++) {
columnNames.addElement(metaData.getColumnName(i));
}
LIKE it's wrong choise becouse your db doesn't use index and will be slow (and doesn't work).
The query is like this:
SELECT * FROM inventoryreport WHERE YEAR(Date_column) = 2014 AND MONTH(Date_column) = 3;
So your code is:
String query = "Select * from inventoryreport where YEAR(InDate) = " +txtYear.getText()+" AND MONTH(InDate) = "+ txtMonth.getText();
I think it is a small mistake in the date format:
Your format : YYYYMM (no seperation symbol)
Right format: YYYY-MM-DD (with a '-' to seperate)
I think
String query = "Select * from inventoryreport where InDate LIKE "+txtYear.getText()+"-"+ txtMonth.getText()+"-00";
should fix it, if your database only includes monthly exact values.
Otherwise you should use
Select * from inventoryreport where InDate BETWEEN '2014-03-18' AND '2014-03-20'
A SQL query can take advantage of indexes when a column in not surrounded by a function. The following where clause would allow the use of indexes:
SELECT *
FROM inventoryreport
WHERE Date_Column >= str_to_date(concat_ws('-', txtYear.getText(), txtMonth.getText(), '01'), '%Y-%m-%d') and
Date_Column < adddate(str_to_date(concat_ws('-', txtYear.getText(), txtMonth.getText(), '01'), '%Y-%m-%d'), interal 1 month)
Although more complicated, all the manipulations are on constants, so the query engine can still take advantage of an index on Date_Column.
I was wondering if using PreparedStatement.setString() was a good idea (possible, sensible?) to dynamically build a query.
For example :
sql code:
SELECT * FROM table1 WHERE table1.category = ? ?
java code:
ps.setString(1,"category1");
ps.setString(2,"AND table1.category = 'category2'");
Also, would it be possible to do something like:
ps.setString(1,"category1");
ps.setString(2," AND table1.category = ?");
ps.setString(3,"category2");
Best regards
Unfortunately, NO.
PreparedStatements are strictly for values only. Table Names and Column Names (as well as conditions in your example) are not allowed. So the best way to do is to concatenate it with the string.
String others = " AND table1.category = ?";
String query = "SELECT * FROM table1 WHERE table1.category = ? " + others;
java code:
ps.setString(1,"category1");
ps.setString(2,"category2");
Whatever you put inside setString will go within single quotes ' ' and will not be interpreted as a query.
I'm trying to change a value Dr_status that only contain one int even 0 or 1. So if Dr_status equal to 1 change it to 0 and vice versa.
Here is the code :
String query = "Select Bluetooth_Address FROM dr";
String str = "40D32DBBE665";//in the database I have only two fields in `Bluetooth_Address` column 40D32DBBE665 and another value
String check = "";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
PreparedStatement preparedStmt= con.prepareStatement("update `dr` set `Dr_status` = '1'");
PreparedStatement preparedStmt1= con.prepareStatement("update `dr` set `Dr_status` = '0'");
dbtime = rs.getString(1);
if (dbtime.equals(str)){
check = "Select `Dr_status` From `dr` Where `Bluetooth_Address` = " + " " + str ;
if(check.equals(0)){
preparedStmt.executeUpdate();
}
if(check.equals(1)){
preparedStmt1.executeUpdate();
}
I don't know where is the problem !!! please help.
Thanks in advance.
I give +1 to the answer from #Marcelo Hernández Rishmawy. Instead of testing the condition in Java code, do the test and the update in an SQL expression that converts 0 to 1 and 1 to 0 automatically, for the rows that match your Bluetooth address condition.
I'll also give you a tip that in MySQL, 1 and 0 are integers, but they are also used for true and false. So you can use either of the following tricks to make the statement more compact:
"update `dr` set `Dr_status` = ! `Dr_status` where `Bluetooth_Address = " + str
This trick works too:
"update `dr` set `Dr_status` = 1 - `Dr_status` where `Bluetooth_Address = " + str
It's a nice way to simplify, but FWIW it's specific to MySQL, not standard SQL. Other databases brands use proper boolean values, not 1 and 0.
Re your comment: the error is not related to the solutions above, it's because you're interpolating a string of hex digits. You need to either quote the string, or better yet use a query parameter.
You should learn how to use query parameters in any case, because they're good for writing secure code to defend against SQL injection issues, and it's generally easier and more robust than trying to interpolate variables into SQL query strings.
See Using Prepared Statements at The Java Tutorials.
Use something similar to:
"update `dr` set `Dr_status` = CASE `Dr_status` WHEN '1' THEN '0' ELSE '1' END CASE Where `Bluetooth_Address` = '" + str + "'"
The line if(check.equals(0)){ is invalid. check is a String and will never equal 0