SQL准备好的语句如何通过多个可能的菜单select来select?

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

菜单select将向托pipebean发送用户select的variables,并使用准备好的语句使用用户select的菜单中的信息(如果有的话)search数据库表。

如果用户离开菜单项为空,它应该search一切。

如果用户离开菜单项的1个,2个或3个信息,另一个为空,则应该相应地进行search。

我的问题是如何做到这一点,而无需附加到每个适当的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门多萨! 我的代码是这样的:

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

更新是的,我不得不使用=“”而不是一个不同的MySQL数据库(可能是不同的版本或东西)

我假设你有一个默认值为NULL选定的值(因为我不知道使用PreparedStatement另一种方式)为'0' (就像一个例子)。

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

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

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


编辑:我已经根据您的要求做了testing。 首先是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); } } 

testing使用MySQL 5.1.18。

我倾向于使用像这样的辅助方法来构builddynamic查询:

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

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