PreparedStatement: Can I supply the column name as parameter? - mysql

Let's say I have a table with 3 columns: C1, C2, C3
I make a search based on the C1 column.
Could I make something similar like this (this is not working - because this is not the way prepareStatement it's used:) )
String c;// the name of the column
...
String sql = "select * from table where ? = ?";
pre = con.prepareStatement(sql);
pre.setString(1, c);
pre.setString(1, i);
rs = pre.executeQuery();
The main idea, I don't want to have 3 ifs for every column. An elegant solution?

This won't work. The prepare statement parses the SQL, sends to the database for validation and compilation. If question marks could substitute parts of the SQL, you would loose the whole point of bound variables - speed and security. You would reintroduce SQL injection back and statements will have to be recompiled for all parameters.
Wouldn't something like SELECT * FROM table WHERE c1 = ? OR c2 = ? OR c3 = ? be better (of course depending on indexes and table sizes).

you could code up a a set of sql queries and store them in a map, then grab one based on the column in question.
enum column { a, b, c}
Map<column, string> str;
static {
str.put(a, "select * from tbl where a = ? ");
...
}
then just grab one out of the map later based on the enum. String appends in sql statements have a way of becoming security problems in the future.

Use a dynamic query and a java.sql.Statement:
String whereClause = c + " = " + i;
// Form the dynamic Query
StringBuffer query = new StringBuffer( "SELECT * FROM TABLE" );
// Add WHERE clause if any
query.append(" WHERE " + whereClause);
// Create a SQL statement context to execute the Query
Statement stmt = con.createStatement();
// Execute the formed query and obtain the ResultSet
ResultSet resultSet = stmt.executeQuery(query.toString());

can't you do this:
String c;// the name of the column
...
String sql = "select * from table where " + c + " = ?";
pre = con.prepareStatement(sql);
pre.setString(1, i);
rs = pre.executeQuery();
?
If not then this might be a solution:
String c;// the name of the column
...
String sql = "select * from table where ('C1' = ? AND C1 = ?)
OR ('C2' = ? AND C2 = ?)
OR ('C3' = ? AND C3 = ?)"
pre = con.prepareStatement(sql);
pre.setString(1, c);
pre.setString(2, i);
pre.setString(3, c);
pre.setString(4, i);
pre.setString(5, c);
pre.setString(6, i);
rs = pre.executeQuery();

Related

How to ensure ordering of multiple parameters when using Dapper + ODBC/MS Access? [duplicate]

This question already has answers here:
Why Dapper does not UPDATE data to MS Access even though no exception?
(2 answers)
Closed 11 months ago.
Normally Dapper queries allow me to do something like this:
string query = "SELECT * FROM some_table WHERE some_value = #MyParameter";
var parameter = new {MyParameter = 20};
connection.Query(query,parameter);
or like this
string query = "SELECT * FROM some_table WHERE some_value = #MyParameter";
var parameter = new DynamicParameters();
parameter.Add("#MyParameter",20);
connection.Query(query,parameter);
This doesn't work with an OdbcConnection because named parameters are not supported. Instead a "?" can be used to mark parameters:
string query = "SELECT * FROM some_table WHERE some_value = ?";
var parameter = new {MyParameter = 20};
connection.Query(query,parameter);
or
string query = "SELECT * FROM some_table WHERE some_value = ?";
var parameter = new DynamicParameters();
parameter.Add("#MyParameter",20);
connection.Query(query,parameter);
This works fine for single parameter, but I cannot find any source telling me what happens with multiple parameters. I've tested the following:
string query = "SELECT * FROM some_table WHERE some_value > ? AND some_value < ?";
var parameter = new {Min= 20, Max =30};
connection.Query(query,parameter);
or
string query = "SELECT * FROM some_table WHERE some_value > ? AND some_value < ?"
var parameter = new DynamicParameters();
parameter.Add("Min",20);
parameter.Add("Max",30);
connection.Query(query,parameter);
And it works just fine, but I'd like to be certain that the order in which I create anonymous object properties or the order in which I add parameters to the DynamicParameter is guaranteed to be preserved.
Thanks to the comment by Amit Joshi I found that "pseudo positional parameters" can be used
string query = "SELECT * FROM some_table WHERE some_value > ?MinValue? AND some_value < ?MaxValue?"
the order of parameters added to DynamicParameters or an anonymous object then no longer matter.

SELECT query not passing parameters

I have an select query with inner join, and the where clause is in the second Query,
Here is the code :
static String Showplan = "SELECT * From plan_audit INNER JOIN (SELECT Du,Au From Programme_audit Where Du = '?' AND Au = '?')AS T ";
public void buttonClick(ClickEvent event) {
try{
Class.forName("com.mysql.jdbc.Driver");
Core.con = DriverManager.getConnection(Core.db,Core.dbUsername,Core.dbPassword);
PreparedStatement st;
st = Core.con.prepareStatement(Core.Showplan);
st.setString(1,select.getValue().toString());
st.setString(2,select1.getValue().toString());
ResultSet rs = st.executeQuery();
while(rs.next()){
table.addItem(new Object[]{rs.getInt(1),rs.getString(2),rs.getDate(3),rs.getString(4), rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8),rs.getDate(9),rs.getString(10),rs.getString(11),rs.getDate(12),rs.getString(13),rs.getString(14),rs.getString(15)},rs.getInt(1));
}
}catch(Exception e){
e.printStackTrace();
}
}
});
and the exception being raised is the following:
java.sql.SQLException: Parameter index out of range (1 > number of
parameters, which is 0).
Don't put single quotes after the parameter markers ?. In fact, don't do anything to them, rather let Java insert the data as it sees fit:
String sql = "SELECT * From plan_audit INNER JOIN ";
sql += "(SELECT Du, Au From Programme_audit Where Du = ? AND Au = ?) t ";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, select.getValue().toString());
st.setString(2, select1.getValue().toString());
ResultSet rs = st.executeQuery();
The whole point of prepared statements is to let Java worry about how to bring your data into the query. In this case, since you are binding strings, they would be surrounded by single quotes, but you do not need to be concerned with this.
As a side note, your query is actually doing a cross join, since you never specify a join condition. This may or may not be what you intend, but most likely you want to have some kind of join condition here.
Have you tried the parameter indexes 0 and 1 instead of 1 and 2?
st.setString(0,select.getValue().toString());
st.setString(1,select1.getValue().toString());
The single quotes are correct.

issue with checking already existing values in table

I want to check of the values in my 3 textfield already exist in my table before proceeding further in my statement but it does not work in eclipse but work in heidisql? prepareStatement and resultset are properlt initislise at the top.
I already try using ? and preStatement.setString(1, get_status_update) but it gave me the same error result.
String get_status_update = stats_status_txta.getText();
String get_username= friend_username_txtf.getText();
String get_friendname= friend_list_txta.getText();
DB_connection db_connection = new DB_connection();
try{
if(get_username.length() < 3) {
JOptionPane.showMessageDialog(statusPanel,"You need to insert a username here","Post Lodge Status Error", JOptionPane.INFORMATION_MESSAGE);
} else if (get_status_update.length() < 3) {
JOptionPane.showMessageDialog(statusPanel,"Please insert the status update you wish to like","Post Lodge Status Error", JOptionPane.INFORMATION_MESSAGE);
} else {
String sql = " SELECT sut.status_update_id, up.user_id , fd.friend_id "
+ "FROM tb_logde_status_update as tsu "
+ "INNER JOIN status_update_tb as sut ON sut.status_update_id = tsu.status_update_id "
+ "INNER JOIN user_profile as up ON tsu.user_id = up.user_id "
+ "INNER JOIN friend_details as fd ON tsu.friend_id = fd.friend_id "
+ "WHERE sut.status_update_msg='"+get_status_update+"' AND up.username='"+get_username+"' AND fd.friend_username='"+get_friendname+"' ";
preStatement = db_connection.connect().prepareStatement(sql);
res = preStatement.executeQuery();
boolean send_logde_status = false;
while (res.next()) {
if(res.getString("status_update_msg").equalsIgnoreCase(get_status_update)
&& res.getString("username").equalsIgnoreCase(get_username)
&& res.getString("friend_username").equalsIgnoreCase(get_friendname)) {
JOptionPane.showMessageDialog(statusPanel, "Status update has already been like by you, choose another one!");
send_logde_status = true;
break; // Get out of the loop. No more need for it.
// Maybe the error is around here?
}
} ...
When I use the query directly from the database query it work!
SELECT sut.status_update_id, up.user_id , fd.friend_id
FROM tb_logde_status_update as tsu
INNER JOIN status_update_tb as sut ON sut.status_update_id = tsu.status_update_id
INNER JOIN user_profile as up ON tsu.user_id = up.user_id
INNER JOIN friend_details as fd ON tsu.friend_id = fd.friend_id
WHERE sut.status_update_msg="not hallo world" AND up.username="username" AND fd.friend_username="paul";
I am inserting the exactly values from my 3 textfields. I am getting the status_update_id, user_id, friend_id when i use the query from the database but not in my action listener button
Error: Column 'status_update_msg' not found.
Maybe the parameters are not exactly the same as the ones passed in the direct query, I would suggest the following:
Log the parameters values in console
Try using trim() and/or toLowerCase() if parameter values need to be in lower case only
Also, using setXXX() methods for preparedStatement is better approach than appending parameter values to a String query.

How to Select records with over 4 criteria

Select records based on the criteria shown
Is there any way i can select records from MySQL based on this criteria apart using the many if else statements.
Actually what i have in mind is below
if CurrentLevel.SelectedItem <> Nothing AND Programme.SelectedItem = Nothing AND Gender.SelectedItem = Nothing Then
myconnection.Open()
Dim SelCmd as SqlCommand = New SqlCommand("Select * From StudentsList Where CurrentLevel = '"& CurrentLevel.SelectedItem &"'",myconnection)
And I'll have to do it for all the possible outcomes.
Which makes the code very lengthy and tiresome to write.
Is there a shorter way of performing this search because I'll perform another search with almost 16 criteria.
The question is not entirely clear to me. You won't need a new if statement for all the criteria. You can achieve this by modifying the SQL query itself. One of the main purpose of SQL is to get data that match certain criteria.
SELECT * FROM StudentsList WHERE `CurrentLevel` = "level" AND `gender` = "male" AND `programme` = "something"
The above SQL query should give you a basic idea. It will select the rows which have CurrentLevel as level, gender as male and programme as something only, the rest will be ignored.
EDIT:
I don't know VB. Here is a quick, dirty example in C# which will help you understand the basic logic behind this.
string sqlQuery = "SELECT * FROM StudentsList ";
if(currentLevelDropDown.SelectedItem.Text != "")
{
sqlQuery + "WHERE CurrentLevel = " + currentLevelDropDown.SelectedItem.Text;
}
if(ProgrammeDropDown.SelectedItem.Text != "")
{
sqlQuery + " AND WHERE programme = " + ProgrammeDropDown.SelectedItem.Text;
}
//Final Query becomes: SELECT * FROM StudentsList WHERE CurrentLevel = userSelectedOption AND WHERE programme = userSelectedProgrammeOption
//Finally execute the sqlQuery

NHibernate CreateSqlQuery and addEntity

The hibernate manual says this:
String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class).list()
Now, what I have is basically the same. I am return two of the same type per row. I am doing a select something like this:
SELECT {ctrl1.*}, {ctrl2.*} FROM tableA AS A
LEFT JOIN tableB AS ctrl1 ON (A.controlID = ctrl1.controlID AND ctrl1.controlOptionType = ? AND ctrl1.controlOptionValue = ?)
LEFT JOIN tableB AS ctrl2 ON (A.controlID = ctrl2.controlID AND ctrl2.controlOptionType = ? AND ctrl2.controlOptionValue = ?)
And then I addEntity("ctrl1", typeof(mycontrolclass) and
addEntity("ctrl1", typeof(mycontrolclass)
Which seems exactly the same to me as their example. But I get this exception:
"Could not execute query" and the inner exception is "Could not find specified column in results".
If I copy the sql in the exception(to which it has added "AS ctrl1_1_3_3_" etc) it works fine.
Thanks.
What exactly are you trying to do? I believe you might not need using either of them.
// Using HQL:
var motherId = 25;
var hql = "select c.birthDate, c.mother from Cat c where c.mother.Id = :motherId";
var result = Session.CreateQuery(hql)
.SetParameter("motherId", motherId)
.ToList();
// Using NHibernate.LINQ:
var result = (from cat in Session.Linq<Cat>()
where cat.Mother.Id == motherId
select new { cat.birthDate, cat.mother }).ToList();
HQL query examples.
LINQ for NHibernate examples.
I dealt with your problem just for studying purposes, because you will surely
have found a solution in the meanwhile, but the problem should not lie in
the query (which is ok), but in some mapping inconsistency or somewhere else
(perhaps Database).