我可以将此模式用于where子句的可选部分吗?

时间:2013-04-23 02:34:09

标签: mysql sql query-optimization prepared-statement

我有很多代码,非常标准的东西。它在java对象中需要一些过滤器,并返回与过滤器匹配的所有记录:

class MarkFilters {
   Integer idFilter;
   Integer userIDFilter;
   Integer claimIDFilter;
}

List<Integer> findMarksMatchingFilters(MarkFilters filters) {
    String sql = "select id from Mark where 1";

    // This has the values to substitute in for the ?'s in the SQL
    List<Object> parameters = new LinkedList<Object>();

    if (filters.idFilter != null) {
        sql += " and id = ?";
        parameters.add(filters.idFilter);
    }

    if (filters.userIDFilter != null) {
        sql += " and userID = ?";
        parameters.add(filters.userIDFilter);
    }

    if (filters.claimIDFilter != null) {
        sql += " and claimID = ?";
        parameters.add(filters.claimIDFilter);
    }

    return executeSQLWithParameters(sql, parameters);
}

我找到了一种应该做同样事情的方法:

List<Integer> findMarksMatchingFilters(MarkFilters filters) {
    return executeSQLWithParameters(
            "select * from Mark " +
            "where (? = NULL or id = ?) " +
            "and (? = NULL or userID = ?) " +
            "and (? = NULL or claimID = ?) ",
        filters.idFilter, filters.idFilter,
        filters.userIDFilter, filters.userIDFilter,
        filters.claimIDFilter, filters.claimIDFilter);
}

例如,如果我输入 new MarkFilters(null,null,3),则sql语句将为:

select * from Mark
where (NULL = NULL or id = NULL)
and (NULL = NULL or userID = NULL)
and (3 = NULL or claimID = 3)

理论上将优化为:

select * from Mark where claimID = 3;

我的具体问题:这种优化究竟会发生吗?

我更广泛的问题:这是一个好的模式,还是我看不到的缺点?

谢谢!

2 个答案:

答案 0 :(得分:1)

没有。表达式NULL = NULL的计算结果为false。

你想:

        "select * from Mark " +
        "where (? is NULL or id = ?) " +
        "and (? is NULL or userID = ?) " +
        "and (? is NULL or claimID = ?) ",

我希望MySQL在编译时评估常量表达式。这意味着在评估之前简化where子句。但是,我在文档中找不到具体的参考资料来保证这一点。

答案 1 :(得分:0)

不完全是答案,但我刚刚找到了我建议的两种方法的替代方案:

http://mybatis.github.io/mybatis-3/dynamic-sql.html#chooseWhenOtherwise