8

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

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

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

如果用户留下 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);
        } 

等等,但是对于每种情况下 1 为空而不是其他情况,我必须这样做 16 次?必须有更聪明的方法(要么使用 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();

更新是的,我不得不使用 = "" 而不是 is null 用于不同的mysql数据库(可能是不同的版本或其他东西)

4

2 回答 2

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 测试。

于 2013-02-27T20:44:29.297 回答
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...

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

于 2013-02-27T20:41:30.610 回答