SQL准备语句如何通过多种可能的菜单选择进行选择?

时间:2013-02-27 20:36:00

标签: java sql jdbc

所以我有4个菜单选项(产品,位置,courseType和类别),所有这些都可以为null(使用JSF编程,但这应该与此问题无关,因为它是一个SQL问题)。

菜单选择将向托管bean发送用户选择的变量,并使用预准备语句使用用户选择的菜单中的信息(如果有)搜索数据库表。

如果用户将菜单项保留为null,则应搜索所有内容。

如果用户将1或2或3个菜单项留下信息,而另一个留空,则应进行相应的搜索。

我的问题是如何在没有附加到适当的sql语句的bean中的一堆if / then语句的情况下执行此操作?

或者是否有一个更好的sql语句我可以做到这一切吗?

我在Java中使用预备语句。

我试过了:

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);
        } 

等等但是我必须这样做16次,因为每个1的情况是空的而不是其他情况? 必须有一个更聪明的方法(通过使用1个sql语句或只有几个java if / then语句?)

感谢Luiggi Mendoza!我的代码是这样的:

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();

更新是的我必须使用=“”而不是null为不同的mysql数据库(可能是不同的版本或其他东西)

2 个答案:

答案 0 :(得分:7)

我假设您NULL所选值的默认值(因为我不知道使用PreparedStatement的另一种方式)作为'0'(仅作为示例) )。

知道这一点,我倾向于使用这种SQL:

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

使用此方法,您可以利用IF用法并让数据库处理工作。唯一不好的一点是,你应该将每个变量设置两次(这一生中没有任何东西是自由的=)。


编辑:我已根据您的要求进行了测试。首先是SQL表和内容:

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');

现在,相关的Java代码:

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);
    }
}

使用MySQL 5.1.18进行测试。

答案 1 :(得分:1)

我倾向于使用这样的辅助方法构建动态查询:

StringBuilder query = new StringBuidler();
query.append("SELECT foo, bar FROM baz");
query.append(buildProductClause(product));
query.append(buildLocationClause(location));
query.append(buildCourseTypeClause(courseType));
// etc...

如果您仍想使用预准备语句,可以使用成员字段构建参数数组。