I have a program that selects from a database given a table and column string.
public void selectAllFrom(String table, String column){
String sql = "SELECT ? FROM ?";
try (Connection conn = this.connect();
PreparedStatement pstmt = conn.prepareStatement(sql)){
pstmt.setString(1, column);
pstmt.setString(2, table);
ResultSet rs = pstmt.executeQuery();
while (rs.next()){
System.out.println(rs.getString(column));
}
} catch (SQLException e){
System.out.println(" select didn't work");
System.out.println(e.getMessage());
}
}
For some reason it is not working and it is going right to catch
Here is the connect() function as well:
private Connection connect(){
Connection conn = null;
// SQLite connection string
String url = "jdbc:sqlite:C:/sqlite/db/chinook.db";
try{
// creates connection to the database
conn = DriverManager.getConnection(url);
System.out.println("Connection to SQLite has been established");
} catch (SQLException e){
System.out.println(e.getMessage());
System.out.println("Connection didn't work");
}
return conn;
}
I know the problem is not with the database because I'm able to run other select queries without parameters. It is the parameters that are giving me the problem. Can anyone tell what the problem is?
A table or column name can't be used as a parameter to PreparedStatement. It must be hard coded.
String sql = "SELECT " + column + " FROM " + table;
You should reconsider the design so as to make these two constant and parameterize the column values.
? is a place holder to indicate a bind variable. When a SQL statement is executed, database first checks syntax, and validates the objects being referenced, columns and access permission for specified objects (i.e metadata about objects) and confirms that all are in place and valid. This stage is called parsing.
Post parsing, it substitutes bind variables to query and then proceeds for actual fetch of results.
Bind variables can be substituted in any place in query to replace an actual hard coded data/strings, but not the query constructs them selves. It means
You can not use bind variables for keywords of sql query (ex: SELECT, UPDATE etc.)
You can not use bind variables for objects or their attributes (i.e table names, column names, functions, procedures etc.)
You can use them only in place of a otherwise hard coded data.
ex: SELECT FIRST_NAME, LAST_NAME, 'N' IS_DELETED FROM USER_DATA WHERE COUNTRY ='CANADA' AND VERIFIED_USER='YES'
In above sample query, 'N','CANADA' and 'YES' are the only strings which can be replaced by a bind variable, not any other word.
Using bind variable is best practice of coding. It improves query performance (when used with large no. of queries in tuned database products like Oracle or MSSQL) and also protects your code against sql injection attacks.
Constructing query by concatenating strings (especially data part of query) is never recommended way. You can still construct a query by concatenation for other parts like table name or column name as long as those strings are not directly taken from input.
Below example is acceptable:
query = "Select transaction_id, transaction_date from ";
if (isHistorical(reportType)
{ query = query + "HISTORY_TRANSACTIONS" ;}
else
{query = query + "PRESENT_TRANSACTIONS" ; }
recommended practice is to use
String query_present = "SELECT transaction_id, transaction_date from PRESENT_TRANSACTIONS";
String query_historical = "SELECT transaction_id, transaction_date from HISTORY_TRANSACTIONS";
if (isHisotrical(reportType))
{
ps.executeQuery(query_historical);
}else{
ps.executeQuery(query_present);
}
Related
I am trying to drop all the functions and procedures in my DB through java.
My current code is like so:
Class.forName(driver);
Connection conn = getConnectionToDB();
String itemName;
ResultSet rs = getResultSetForItem(item);
String upperCaseItem = item.toUpperCase();
while (rs.next()) {
itemName = rs.getString(upperCaseItem + "_NAME");
// Procedure and function names come with a grouping ID, remove it
if (item.equals("procedure") || item.equals("function"))
itemName = itemName.substring(0, itemName.indexOf(";"));
stmt = conn.createStatement();
stmt.executeUpdate(query + " " + itemName);
}
Where item is once "function" and once "procedure". Also, the query variable is set correctly to be "DROP FUNCTION" or "DROP PROCEDURE" respective to the execution.
The method of getResuletSetForItem:
Class.forName(driver);
Connection conn = getConnectionToDB();
DatabaseMetaData md = conn.getMetaData();
switch (item.toLowerCase()){
case "function":
rs = md.getFunctions("LDMS", "dbo", "%");
break;
case "procedure":
rs = md.getProcedures("LDMS", "dbo", "%");
break;
}
return rs;
What happens is, I get the resultset as functions or procedures according to what I am asking for. BUT it returns also the records for the other kind (Meaning, if I asked for a ResultSet of functions, I also get the procedures as well).
This of course causes an exception when I try to, for example, execute "DROP FUNCTION X" where X is actually a stored procedure.
Although you don't explictly say so, it looks like you might be using the MS SQL Server driver for Java.
From the documentation it looks like the getFunctions and getProcedures methods both return a list of functions and procedures. You need to evaluate the FUNCTION_TYPE column to determine which is which.
The type of the function. It can be one of the following values:
SQL_PT_UNKNOWN (0)
SQL_PT_PROCEDURE (1)
SQL_PT_FUNCTION (2)
Please tell me how to solve the error from the code. I want to get the details from the ms access table. I have used data and description as columns. date is the primary key in ms access. so please let me help me with reading the data from ms access table.
try{
connect();
stmt = (Statement) conn.createStatement();
String sql, ks = " ";
ks = JOptionPane.showInputDialog("enter the date of which you want to read");
String jk = " where date=" + ks;
sql = "SELECT [date],[description] FROM Table2" + jk;
System.out.println("1");
rs = ((java.sql.Statement) stmt).executeQuery(sql);
if(rs.next())
{
String date1="hello",description1="hii";
date1 = rs.getString("date");
description1=rs.getString("description");
JOptionPane.showMessageDialog(null,"Date:"+date1+"\n"+description1);
}
else
{
JOptionPane.showMessageDialog(null,"Sorry the record does not exist");
try
{
close();
}
catch(Exception ea)
{
JOptionPane.showMessageDialog(null, "Error:"+ea.getMessage());
}
}
}
catch(Exception ew)
{
JOptionPane.showMessageDialog(null, "Unable to fetch Data");
JOptionPane.showMessageDialog(null,""+ew.getMessage());
System.out.println(""+ew);
}
Thanks
Your error message says that there is a syntax error in your SQL query. In your example, it seems to be:
SELECT [date],[description] FROM Table2 where date=19apr2015.
This is wrong as the date (19apr2015) does not have the correct format.
A correct SQL query would be:
SELECT [date],[description] FROM Table2 where date=#4/19/2015#
So you will have to parse the user input and convert it into the correct form, or request the user to enter the date in the correct form.
SQL injection
In both cases it is adviced to use a PreparedStatement with the date as parameter instead of putting together the SQL statement using string concatenation, as the latter is dangerous because of an evil thing called SQL injection! For example, imagine, the user wants to do any harm and instead of entering a valid date, he/she enters
#1/1/2000#; DELETE * FROM Table2
So the following SQL statement would be executed by your database:
SELECT [date],[description] FROM Table2 where date=#1/1/2000#; DELETE * FROM Table2
The second statement would simple delete all your data! (To be exact, the statement above would fail as MS Access does not support to chain multiple statements, but other database systems do support this, so this is a security leak that is sleeping until you migrate your database. Apart from that, there are other ways to do SQL injection in MS Access, e.g. by using Subqueries.)
By using a PreparedStatement you can avoid this issue. Apart from that it is more convenient to program:
Date date = /* java.sql.Date-object created from user input */
try (PreparedStatement stmt = conn.prepareStatement(
"SELECT [date],[description] FROM Table2 where date=?")
) {
// set first (and only) parameter value
stmt.setDate(1, date);
// execute statement
try (ResultSet result = stmt.executeQuery()) {
// process result as usual
}
}
int rs = stmt.executeUpdate("INSERT INTO Leden VALUES (null,"+u+","+p+",'1')");
I'm getting the error
java.sql.SQLException: Unknown column '(the U variable)' in 'field list';
I know for sure it is 100% the "" but i can't seem to find it where it goes wrong
any help is appreciated!
This is my whole method (I want to learn how to do it with a prepared statement)
public static void connectionDB(String u, String p, String f){
{
try {
String username = "/////////";
String password = "///////";
String url = "///////////////";
Connection connection = DriverManager.getConnection(url, username, password);
Statement stmt = connection.createStatement();
int rs = stmt.executeUpdate("INSERT INTO Leden VALUES (null,'"+u+"','"+p+"','1')");
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("Database connected!");
}
}
It should be like
int rs = stmt.executeUpdate("INSERT INTO Leden VALUES (null,'"+u+"','"+p+"','1')");
Update:-
You can also look into prepared statements because
Prepared statements are much faster when you have to run the same statement multiple times, with different data. Thats because SQL will validate the query only once, whereas if you just use a statement it will validate the query each time.
Assuming fields are A,B,C,D;
A is int and remains are strings
String insertTableSQL = "INSERT INTO Leden"
+ "(A,B,C,D) VALUES"
+ "(?,?,?,?)";
preparedStatement.setInt(1, 11);
preparedStatement.setString(2, "Hello");
preparedStatement.setString(3, "this");
preparedStatement.setString(4, "OP");]
preparedStatement .executeUpdate();
It should be
int rs = stmt.executeUpdate("INSERT INTO Leden VALUES (null,'"+u+"','"+p+"','1')'");
The issue is, that " is used in SQL for objects like columns or tables, whereas ' is used for strings. So in +u+, which seems to not exists in context of your query.
Your query itself should therefore look something like (given, that +u+ and +p+ are strings.
INSERT INTO Leden VALUES (null,'+u+','+p+','1')
If you need to have " inside your columns, it would read like
INSERT INTO Leden VALUES (null,'"+u+"','"+p+"','1')
Also I would recommend to specify the columns you are inserting to so it looks similar to:
INSERT INTO "Leden" ("col1", "col2", "col3", "col4") VALUES (null,'+u+','+p+','1')
This will prevent your query from failing when extending table definition by another column.
Also using prepared statements could be a good idea here, as it helps you preventing from e.g. SQL injections.
I have a MySQL table with entries already in it and I have it connected to my Java program so it displays the table values whenever the program is run. I'm basically trying to implement a search field where the user can type any attribute's value and all the entries that match that value will be loaded into the table. Then the user will be able to select the right entry that matches and they can edit, or update that entry's information. This would be useful for me particularly when you have entries that have the same value, for instance first name, last name, or zip code.
try {
String sql = "SELECT * FROM donors WHERE donor_id = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, txtSearch1.getText());
rs = ps.executeQuery();
tblDonors.setModel(DbUtils.resultSetToTableModel(rs));
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
try {
String sql = "SELECT * FROM donors WHERE first_name = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, txtSearch1.getText());
rs = ps.executeQuery();
tblDonors.setModel(DbUtils.resultSetToTableModel(rs));
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
The search field only searches for the second query, but not the first, so I can type a name and the matching names will load into the table, but when I try to input an id number, nothing happens. I'm fairly new to this, but I think it has something to do with my resultset object? Not exactly sure though. Any help would be great.
What happens here is that the second result overwrites the first. I think the easiest solution is to use or in the where clause, like this:
String sql = "SELECT * FROM donors WHERE (donor_id = ?) or (first_name = ?)";
ps.setString(1, txtSearch1.getText());
// but of course there are 2 ?'s now, we have to give the value to the second one
// as well
ps.setString(2, txtSearch1.getText());
Due to the way placeholders work in JDBC you'll have to provide a value for each ?.
I get a parameter is called 'id' in my function and want to print the cell of the name of this id row.
for example:
this is my table:
id name email
1 alon alon#gmail.com
I send to my function: func(1), so I want it to print 'alon'.
this is what I tried:
static final String url = "jdbc:mysql://localhost:3306/database_alon";
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection(url, "root", "Admin");
String query_txt = "SELECT * FROM authors WHERE id = " + id;
Statement ps2 = con.createStatement();
ResultSet my_rs = ps2.executeQuery(query_txt);
System.out.println(my_rs.getString("name"));
con.close;
Everything is fine, but just one problem. You need to move your ResultSet cursor to the first row before fetching any values: -
Use: -
ResultSet my_rs = ps2.executeQuery(query_txt);
while (my_rs.next()) {
System.out.println(my_rs.getString("name"));
}
As a side note, consider using PreparedStatement to avoid getting attacked by SQL Injection.
Here's how you use it: -
PreparedStatement ps2 = con.prepareStatement("SELECT * FROM authors WHERE id = ?");
ps2.setInt(1, id);
ResultSet my_rs = ps2.executeQuery();
while (my_rs.next()) {
System.out.println(my_rs.getString("name"));
}
You need to use ResultSet.next() to navigate into the returned data:
if (my_rs.next()) {
System.out.println(my_rs.getString("name"));
}
Call my_rs.next(), which will move the ResultSet cursor onto the first row (which you are extracting data out of).
If this is a real application, use PreparedStatements instead of generic Statements. This is an extremely important matter of security if you plan on using user input in SQL queries.