Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL prepared statement how to select via multiple possible menu selections?

Tags:

java

sql

jdbc

So I have 4 menu selections (product, location, courseType, and category), all of which can be null (programmed using JSF but that should be irrelevant to this question, as it is an SQL question).

The menu selection will send the managed bean the variable that the user selected, and using a prepared statement search a database table using the information from the menu that the user selected (if any).

If the user leaves the menu item null, it should search everything.

If the user leaves 1 or 2 or 3 of the menu items with information, and the other one null, it should search accordingly.

My problem is how do I do this without a bunch of if/then statements in the bean attached to an the appropriate sql statement for every one?

Or is there one better sql statement I can make that does all of this?

I am using a prepared statement in Java.

I tried this:

if (product != null && location != null && courseType != null && category != null) {
            pstmt = conn.prepareStatement("select * FROM Courses WHERE "
                    + "product = ? "
                    + "and location = ? "
                    + "and courseType = ? "
                    + "and category = ?");

            pstmt.setString(1, product);
            pstmt.setString(2, location);
            pstmt.setString(3, courseType);
            pstmt.setString(4, category);
        } else if (product == null && location != null && courseType != null && category != null) {
            pstmt = conn.prepareStatement("select * FROM Courses WHERE "
                    + "location = ? "
                    + "and courseType = ? "
                    + "and category = ?");


            pstmt.setString(1, location);
            pstmt.setString(2, courseType);
            pstmt.setString(3, category);
        } 

etc etc but I would have to do this like 16 times for each case of 1 being null and not the others? There must be a smarter way (either by using 1 sql statement or only a few java if/then statements?)

UPDATE thanks to Luiggi Mendoza! My code works like this:

pstmt = conn.prepareStatement("select * FROM Courses WHERE " 
         + "(product = ? or ? is null) " 
         + "and (location = ? or ? is null) " 
         + "and (courseType = ? or ? is null)" 
         + "and (category = ? or ? is null)"); 

         pstmt.setString(1, product);
         pstmt.setString(2, product);
         pstmt.setString(3, location);
         pstmt.setString(4, location);
         pstmt.setString(5, courseType);
         pstmt.setString(6, courseType);
         pstmt.setString(7, category);
         pstmt.setString(8, category);


        rset = pstmt.executeQuery();

Update yeah I had to use = "" instead of is null for a different mysql database (maybe different versions or something)

like image 961
Armando Perea Avatar asked Feb 27 '13 20:02

Armando Perea


1 Answers

I assume that you have a default value for your NULL selected values (since I don't know another way to do it using PreparedStatement) as '0' (just as an example).

Knowing this, I tend to use this kind of SQL:

SELECT *
FROM Courses
WHERE
    (product = ? or ? = '0')
    and (location = ?  or ? = '0')
    and (courseType = ? or ? = '0')
    and (category = ? or ? = '0')

With this approach, you leverage the IF usage and let the database handle the work. The only bad point with this is that you should set every variable twice (nothing is free in this life =\ ).


EDIT: I've made a test based on your requirement. First the SQL table and content:

create table pruebaMultiSelect
(id int primary key auto_increment,
nombre varchar(50),
tipo varchar(10),
categoria varchar(10));

insert into pruebaMultiSelect values
(null, 'Luiggi', 'A', 'X');

insert into pruebaMultiSelect values
(null, 'Thomas', 'A', 'Y');

insert into pruebaMultiSelect values
(null, 'Jose', 'B', 'X');

insert into pruebaMultiSelect values
(null, 'Trina', 'B', 'Y');

Now, the relevant Java code:

public class DBTest {

    public void testPreparedStatement(String p1, String p2) throws SQLException {
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = getConnection();
            pstmt = con.prepareStatement("SELECT * FROM pruebaMultiSelect WHERE (tipo = ? OR ? = 'EMPTY') "
                    + "AND (categoria = ? OR ? = 'EMPTY')");
            pstmt.setString(1, p1);
            pstmt.setString(2, p1);
            pstmt.setString(3, p2);
            pstmt.setString(4, p2);
            rs = pstmt.executeQuery();
            while (rs.next()) {
                System.out.printf("%5d %15s\n", rs.getInt(1), rs.getString(2));
            }
        } catch(ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            rs.close();
            pstmt.close();
            con.close();
        }
    }

    public Connection getConnection() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/luiggi_test", "user", "password");
    }

    public static void main(String[] args) throws SQLException {
        //this will return all the data
        String p1 = "EMPTY";
        String p2 = "EMPTY";
        new DBTest().testPreparedStatement(p1, p2);
    }
}

Tested using MySQL 5.1.18.

like image 56
Luiggi Mendoza Avatar answered Oct 14 '22 11:10

Luiggi Mendoza