I have a problem with a search form in a JSP project. In particular an user can subscribe to an event and the admin must be able to search all the members of that event.
I write a form like this:
out.println("<fieldset><legend>Search</legend><form action=\"cercaIscritti.jsp\" method=\"post\">"
+ "Name: <input name=\"name\" type=\"text\"><br>Surname: <input name=\"surname\" type=\"text\"><br>"
+ "Belonging: <input name=\"belonging\" type=\"text\"><br>Countr: <input name=\"country\" type=\"text\"><br>"
+ "<input type=\"submit\" value=\"Cerca\"></fieldset></form>");
(If it isn't readable: there are four <input>, one for each column in the table user and a <input> for submit).
I would like all the fields to be optional so that the admin can fill what it wants, but how do I build the query?
I tried something like this :
public ResultSet searchSubs(String name, String surname, String belonging, String country) {
try {
boolean n = false, s = false, b = false, c = false;
String query = "SELECT * FROM user WHERE ";
if (!isEmpty(name)) {
query += "firstName = ?";
n = true;
}
if (!isEmpty(surname)) {
if (n) {
query += " AND lastName = ?";
} else {
query += "lastName = ?";
}
s = true;
}
if (!isEmpty(belonging)) {
if (n || s) {
query += " AND belonging = ?";
} else {
query += "belonging = ?";
}
b = true;
}//and go on
But how can I add the values with the PreparedStatement? Is this the correct way? If it's not, how can I do something like that?
The booleans are there in the middle only for test, I thought I would use them in some way but I do not know how.
Here is a way you can follow to search with multiples values :
public ResultSet searchSubs(String name, String surname, String belonging, String country){
try {
String query = "SELECT * FROM user WHERE 1=1";
//---------------------------------------^^^
int index = 1;
if (!name.isEmpty()) {
query += " AND firstName = ?";
}
if (!surname.isEmpty()) {
query += " AND surname = ?";
}
if (!belonging.isEmpty()) {
query += " AND belonging = ?";
}
if (!country.isEmpty()) {
query += " AND country = ?";
}
PreparedStatement ps = connection.prepareStatement(query);
if (!name.isEmpty()) {
ps.setString(index++, name);
}
if (!surname.isEmpty()) {
ps.setString(index++, surname);
}
if (!belonging.isEmpty()) {
ps.setString(index++, belonging);
}
if (!country.isEmpty()) {
ps.setString(index++, country);
}
ResultSet rs = ps.executeQuery();
//...
The idea is simple :
In the Where clause use 1=1 to not get an error if the user not enter any value(in this case your query is SELECT * FROM user WHERE 1=1 and it will return every thing)
The first part if to fill the query with the non empty fields
The second if to fill the prepared statement with the right values.
finally execute the prepared statement and get the results.
Related
How to make this one work? Obviously I don't know some very basic staff about SQL queries inside other SQL queries in Java but searching around didn't help!
Thank you in advance
try (Connection con = L2DatabaseFactory.getInstance().getConnection())
{
PreparedStatement stm = con.prepareStatement("SELECT count,owner_id FROM items WHERE item_id=57 order by count desc limit 10");
ResultSet rSet = stm.executeQuery();
while (rSet.next())
{
int owner_id = rSet.getInt("owner_id");
int count = rSet.getInt("count");
if (count == 0)
{
continue;
}
PreparedStatement stm1 = con.prepareStatement("SELECT char_name,accesslevel,online FROM characters WHERE obj_Id=" + owner_id);
ResultSet rSet1 = stm1.executeQuery();
while (rSet1.next())
{
int accessLevel = rSet.getInt("accesslevel");
if (accessLevel > 0)
{
continue;
}
String pl = rSet.getString("char_name");
int online = rSet.getInt("online");
String status = online == 1 ? "<font color=\"00FF00\">Online</font>" : "<font color=\"FF0000\">Offline</font>";
sb.append("<tr><td>"+ pl +"</td><td>"+ count +"</td><td>"+ status +"</td></tr>");
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error", e);
}
It looks like you are trying to join two tables using Java code. This is not such a great idea and not good for performance. Let the database do the joins for you - it is an expert at that. Do not code "inner joins" in Java.
Apart from that: the prepared statements are not being closed and this will sooner or later cause you trouble with OS resources.
My suggestion would be to create one single query with an inner join or a select in statement and also close all prepared statements using try with resources. Something along these lines:
private String test() throws SQLException {
StringBuilder sb = new StringBuilder();
int count = 0;
try (Connection con = L2DatabaseFactory.getInstance().getConnection()) {
try (PreparedStatement stm1 = con.prepareStatement(
"SELECT char_name,accesslevel,online FROM characters WHERE obj_Id in (SELECT owner_id FROM items WHERE item_id=57 order by count desc limit 10)")) {
ResultSet rSet = stm1.executeQuery();
while (rSet.next()) {
count++;
int accessLevel = rSet.getInt("accesslevel");
if (accessLevel > 0) {
continue;
}
String pl = rSet.getString("char_name");
int online = rSet.getInt("online");
String status = online == 1 ? "<font color=\"00FF00\">Online</font>" : "<font color=\"FF0000\">Offline</font>";
sb.append("<tr><td>" + pl + "</td><td>" + count + "</td><td>" + status + "</td></tr>");
}
}
} catch (Exception e) {
Logger.getLogger("test").log(Level.SEVERE, "Error", e);
}
return sb.toString();
}
I've made a search tool in java.
String query = "SELECT * FROM Customer WHERE 1 = 1 ";
if (!firstname.isEmpty()) query += "AND cName = '" + firstname + "' ";
if (!lastname.isEmpty()) query += "AND cLastName = '" + lastname + "' ";
if (!epost.isEmpty()) query += "AND cEpost = '" + epost + "' ";
if (!phonenumber.isEmpty()) query += "AND cPhonenumber '" + phonenumber + "' ";
That ouput this if all of those paramerets has values:
SELECT * FROM Customer WHERE 1 = 1
AND cName = 'test'
AND cLastName = 'test1'
AND cEpost = 'test2'
AND cPhonenumber 'test3'
This way I can get better results by filling in more data, but i can still choose to not do.. I need a solution for JPA for this.. any tips?
Thanks!
EDIT: End result based on the answer below:
public static List<Customer> searchCustomersByParameters(String firstname, String lastname,
String epost, String phonenumber) {
String sql = "SELECT c FROM Customer c WHERE 1 = 1 ";
if (!firstname.isEmpty()) sql += "AND c.cName = :firstname ";
if (!lastname.isEmpty()) sql += "AND c.cLastName = :lastname ";
if (!epost.isEmpty()) sql += "AND c.cEpost = :epost ";
if (!phonenumber.isEmpty()) sql += "AND c.cPhonenumber = :phonenumber";
Query q = em.createQuery(sql);
if (!firstname.isEmpty()) q.setParameter("firstname", firstname);
if (!lastname.isEmpty()) q.setParameter("lastname", lastname);
if (!epost.isEmpty()) q.setParameter("epost", epost);
if (!phonenumber.isEmpty()) q.setParameter("phonenumber", phonenumber);
return q.getResultList();
}
While it is of course possible to create dynamic SQL using string concatenation as suggested in this answer, a more type safe and less risky (in terms of SQL injection) approach is to use the JPA criteria API
public static List<Customer> searchCustomersByParameters(String firstname, String lastname,
String epost, String phonenumber) {
var qb = em.getCriteriaBuilder();
var query = qb.createQuery(Customer.class);
var root = query.from(Customer.class);
query.select(root);
if (!firstname.isEmpty()) query.where(qb.equal(root.get("cName"), firstName));
if (!lastname.isEmpty()) query.where(qb.equal(root.get("cLastName"), lastname));
if (!epost.isEmpty()) query.where(qb.equal(root.get("cEpost "), epost ));
if (!phonenumber.isEmpty()) query.where(qb.equal(root.get("cPhonenumber "), phonenumber));
return em.createQuery(query).getResultList();
}
... or if you don't strictly need to use JPQL you could also use a third party SQL builder like jOOQ:
public static List<Customer> searchCustomersByParameters(String firstname, String lastname,
String epost, String phonenumber) {
return
ctx.selectFrom(CUSTOMER)
.where(!firstname.isEmpty() ? CUSTOMER.CNAME.eq(firstname) : noCondition())
.and(!lastname.isEmpty() ? CUSTOMER.CLASTNAME.eq(lastname) : noCondition())
.and(!epost.isEmpty() ? CUSTOMER.CEPOST.eq(epost) : noCondition())
.and(!phonenumber.isEmpty() ? CUSTOMER.CPHONENUMBER.eq(phonenumber) : noCondition())
.fetchInto(Customer.class);
}
Disclaimer: I work for the company behind jOOQ
use ? and set Parameters for preventing sql injection and in JPA you can use native sql as old way you do and also JPQL.Generate your sql by conditions and set your parameters.I use here where 1=1 condition to easy append next conditions by and.Otherwise you will have difficulties for appending "where" to your sql.
by native:
public static List<YourEntity> getFromTable(String name,String surname) {
EntityManager em = PersistenceManager.instance().createEntityManager();
try {
String sql = " select * from table where 1=1 ";
if(name!=null && !name.trim().isEmpty()){
sql +=" and name = :name";
}
if(surname!=null && !surname.trim().isEmpty()){
sql +=" and surname = :surname";
}
Query q = em.createNativeQuery(sql);
if(name!=null && !name.trim().isEmpty()){
q.setParameter("name", name);
}
if(surname!=null && !surname.trim().isEmpty()){
q.setParameter("surname", surname);
}
List<YourEntity> l = q.getResultList();
return l;
} finally {
em.close();
}
}
By jpql:
public static List<YourEntity> getFromTable(String name,String surname) {
EntityManager em = PersistenceManager.instance().createEntityManager();
try {
String sql = " select e from YourEntity e where 1=1 ";
if(name!=null && !name.trim().isEmpty()){
sql +=" and e.name = :name";
}
if(surname!=null && !surname.trim().isEmpty()){
sql +=" and e.surname = :surname";
}
Query q = em.createQuery(sql);
if(name!=null && !name.trim().isEmpty()){
q.setParameter("name", name);
}
if(surname!=null && !surname.trim().isEmpty()){
q.setParameter("surname", surname);
}
List<YourEntity> l = q.getResultList();
return l;
} finally {
em.close();
}
}
I am trying to get this function to only insert the author if the author does not exist in the database.
If the author is already inside the 'authors' table (meaning same first name and same last name) then I want this function to not insert the author BUT I still want it to return the author's ID and I'm not sure how to do this.
Here is my insertAuthor function that inserts the author even if he already exists:
public static int insertAuthor(Connection conn, Author author) throws SQLException
{
ResultSet keys = null;
int authorId;
// Insert the new Authors into the authors table
String sqlInsertAuthor = "INSERT into authors"
+ "(author_firstname, author_lastname)"
+ " VALUES (?, ?)";
try (PreparedStatement statement = conn.prepareStatement(sqlInsertAuthor, Statement.RETURN_GENERATED_KEYS);)
{
statement.setString(1, author.getFirstName());
statement.setString(2, author.getLastName());
// Execute and return number of rows affected
int affectedRows = statement.executeUpdate();
// The number of affected rows should be equal to 1
if (affectedRows == 1)
{
keys = statement.getGeneratedKeys();
keys.next();
authorId = keys.getInt(1);
}
else
{
return 0;
}
}
catch (SQLException e)
{
System.err.println("ERROR INSERTING AUTHOR: " + e.getMessage());
return 0;
}
return authorId;
}
Well, there are several ways to do it.
You can use hibernate and it's 2nd level cache to load all authors and check the first and last name.
You can set the lastname to be unique - it would raise an error if lastname already exists.
You can do it manually - Just check if the first and last name already exists (select count where firstname and lastname). If 0 add new row.
Etc.
If you want the id the last solution would be probably the best: instead of count you could select an in - if there is none, there will be null.
Ok I managed to get what I wanted while I was attempting the select count idea by kamirru.
Here is the working code:
public static int insertAuthor(Connection conn, Author author) throws SQLException
{
ResultSet keys = null;
int authorId;
// Insert the new Authors into the authors table
String sqlInsertAuthor = "INSERT into authors"
+ "(author_firstname, author_lastname)"
+ " VALUES (?, ?)";
try (PreparedStatement statement = conn.prepareStatement(sqlInsertAuthor, Statement.RETURN_GENERATED_KEYS);)
{
// Check if author already exists, if yes return his id
authorId = authorExists(conn, author.getFirstName(), author.getLastName());
// If 0 is returned then the author does not exist so insert the author
if (authorId == 0)
{
statement.setString(1, author.getFirstName());
statement.setString(2, author.getLastName());
// Execute and return number of rows affected
int affectedRows = statement.executeUpdate();
// The number of affected rows should be equal to 1
if (affectedRows == 1)
{
keys = statement.getGeneratedKeys();
keys.next();
authorId = keys.getInt(1);
}
else
{
return 0;
}
}
}
catch (SQLException e)
{
System.err.println("ERROR INSERTING AUTHOR: " + e.getMessage());
return 0;
}
return authorId;
}
public static int authorExists(Connection conn, String firstName, String lastName) throws SQLException
{
int authorId = 0;
// Select the author to check if he exists
String sqlCountAuthor = "SELECT author_id"
+ " FROM authors"
+ " WHERE author_firstname = ? AND author_lastname = ?";
ResultSet rs = null;
try (PreparedStatement statement = conn.prepareStatement(sqlCountAuthor);)
{
statement.setString(1, firstName);
statement.setString(2, lastName);
rs = statement.executeQuery();
// If a result is returned then the author already exists so take his id
if (rs.next())
{
authorId = rs.getInt("author_id");
}
}
catch (SQLException e)
{
System.err.println("ERROR SELECTING AUTHOR: " + e.getMessage());
}
finally
{
if (rs != null)
{
rs.close();
}
}
return authorId;
}
how could i subtract a value based on the input on the text field directly to my database?
and how can i execute two queries at the same time i tried doing this but i had no luck
heres the code i am trying to execute
String sql1 = "select seat from passenger_details where seat = '"+seats+"'";
resultset = statement.executeQuery(sql1);
int count = 0;
while(resultset.next()) {
count = count + 1;
}
if(cc.equals("")||add.equals("")) {
JOptionPane.showMessageDialog(null,"Please Complete the form");
} else {
sql1 = "INSERT INTO passenger_details(fname,lname,gender,address,cc_no,bank_name,no_of_tickets,seat) VALUES('"+fnm+"','"+lnm+"','"+gnd+"','"+add+"','"+cc+"','"+bank+"','"+tckts+"','"+seats+"'),('"+fnm+"','"+lnm+"','"+gnd+"','"+add+"','"+cc+"','"+bank+"','"+tckts+"','"+seats2+"'),('"+fnm+"','"+lnm+"','"+gnd+"','"+add+"','"+cc+"','"+bank+"','"+tckts+"','"+seats3+"'),('"+fnm+"','"+lnm+"','"+gnd+"','"+add+"','"+cc+"','"+bank+"','"+tckts+"','"+seats4+"'),('"+fnm+"','"+lnm+"','"+gnd+"','"+add+"','"+cc+"','"+bank+"','"+tckts+"','"+seats5+"')";
String sql2 = "Update flight_details set seats_avail= seats_avail-'"+tckts+" Where route_name = '"+dest+"'";
statement.addBatch(sql1);
statement.addBatch(sql2);
statement.executeBatch();
JOptionPane.showMessageDialog(null,"Sucess");
}
I am trying to make a simple login System. And This is the coed in database class. Is my Method correct? It should return true if both username and password are correct and false if either one of them is wrong or not in the database(not registered)? Is there any simpler way to code this method?
public boolean getAccount(String name, String password) {
int test = 0;
database = getReadableDatabase();
String sql = "SELECT * FROM tbl_account WHERE username='name' AND password='password'";
Cursor c = database.rawQuery(sql, null);
if (c.moveToFirst()) {
do {
if (c.getString(0).isEmpty()) {
test = 0;
}
else if (c.getString(0).isEmpty() == false) {
if (name.equals(c.getString(0))) {
if (c.getString(1).isEmpty()) {
test = 0;
}
else if (password.equals(c.getString(1))) {
test = 1;
}
}
}
} while (c.moveToNext());
}
if (test == 0) {
return false;
} else {
return true;
}
}
Best practice is to use ? placeholders with selection arguments where you can:
String sql = "SELECT * FROM tbl_account WHERE username = ? AND password = ?";
Cursor c = database.rawQuery(sql, new String[] {name, password});
This avoids problems where the arguments themselves contain characters such as quotes and apostophes that could otherwise break your constructed SQL string.
I think your sql should be:
String sql = "SELECT * FROM tbl_account WHERE username='" + name +
"' AND password='" + password + "'";
try this sql. hope it will help.