WHERE Clause Support

This library supports the creation of very flexible WHERE clauses. WHERE clauses can be added to DELETE, SELECT, and UPDATE statements. WHERE clauses can also stand alone for use in other hand coded SQL.

Simple WHERE Clauses

The simplest WHERE clause is of this form:

        SelectStatementProvider selectStatement = select(count())
                .from(simpleTable)
                .where(id, isEqualTo(3))
                .build()
                .render(RenderingStrategies.MYBATIS3);

The library ships with a wide variety of conditions that can be used in WHERE clauses including “in”, “like”, “between”, “isNull”, “isNotNull”, and all the normal comparison operators. For example:

        SelectStatementProvider selectStatement = select(count())
                .from(simpleTable)
                .where(id, isBetween(3).and(6))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        SelectStatementProvider selectStatement = select(count())
                .from(simpleTable)
                .where(id, isIn(3,4,5))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        SelectStatementProvider selectStatement = select(count())
                .from(simpleTable)
                .where(id, isNotNull())
                .build()
                .render(RenderingStrategies.MYBATIS3);

Complex WHERE Clauses

Conditions can be “anded” and “ored” in virtually any combination. For example:

        SelectStatementProvider selectStatement = select(count())
                .from(simpleTable, "a")
                .where(id, isGreaterThan(2))
                .or(occupation, isNull(), and(id, isLessThan(6)))
                .build()
                .render(RenderingStrategies.MYBATIS3);

Subqueries

Most of the conditions also support a subquery. For example:

        SelectStatementProvider selectStatement = select(column1.as("A_COLUMN1"), column2)
                .from(table, "a")
                .where(column2, isIn(select(column2).from(table).where(column2, isEqualTo(3))))
                .or(column1, isLessThan(d))
                .build()
                .render(RenderingStrategies.MYBATIS3);

Stand Alone Where Clauses

Although rare, you can use the where clause support on its own if you would rather code your own SQL for the remainder of a statement. There may be several reasons to do this - mainly if the library doesn't support some SQL or MyBatis feature you want to use. A good example would be if you want to append other SQL to the generated SQL produced by the library. If you want to use a stand alone where clause, you can code a mapper method that looks like this:

    @Select({
        "select id, animal_name, brain_weight, body_weight",
        "from AnimalData",
        "${whereClause}"
    })
    @ResultMap("AnimalDataResult")
    List<AnimalData> selectWithWhereClause(WhereClauseProvider whereClause);

You can build a stand alone where clause and call your mapper like this:

    Optional<WhereClauseProvider> whereClause = where(id, isNotBetween(10).and(60))
            .build()
            .render(RenderingStrategies.MYBATIS3);

    List<AnimalData> animals = whereClause.map(wc -> mapper.selectWithWhereClause(wc)).orElse(Collections.emptyList());

This method works well when there are no other parameters needed for the statement and when there are no table aliases involved. If you have those other needs, then see the following.

Table Aliases

If you need to use a table alias in the generated where clause you can supply it on the render method using the TableAliasCalculator class. For example, if you have a mapper like this:

    @Select({
        "select a.id, a.animal_name, a.brain_weight, a.body_weight",
        "from AnimalData a",
        "${whereClause}"
    })
    @ResultMap("AnimalDataResult")
    List<AnimalData> selectWithWhereClauseAndAlias(WhereClauseProvider whereClause);

Then you can specify the alias for the generated WHERE clause on the render method like this:

    Optional<WhereClauseProvider> whereClause = where(id, isEqualTo(1), or(bodyWeight, isGreaterThan(1.0)))
            .build()
            .render(RenderingStrategies.MYBATIS3, TableAliasCalculator.of(animalData, "a"));

    List<AnimalData> animals = whereClause.map(wc -> mapper.selectWithWhereClauseAndAlias(wc)).orElse(Collections.emptyList());

It is more likely that you will be using table aliases with hand coded joins where there is more than on table alias. In this case, you supply a Map<SqlTable, String> to the TableAliasCalculator that holds an alias for each table involved in the WHERE clause.

Handling Multiple Parameters

By default, the WHERE clause renderer assumes that the rendered WHERE clause will be the only parameter to the mapper method. This is not always the case. For example, suppose you have a paginated query like this (this is HSQLDB syntax):

    @Select({
        "select id, animal_name, brain_weight, body_weight",
        "from AnimalData",
        "${whereClauseProvider.whereClause}",
        "order by id",
        "OFFSET #{offset,jdbcType=INTEGER} LIMIT #{limit,jdbcType=INTEGER}"
    })
    @ResultMap("AnimalDataResult")
    List<AnimalData> selectWithWhereClauseLimitAndOffset(@Param("whereClauseProvider") WhereClauseProvider whereClause,
            @Param("limit") int limit, @Param("offset") int offset);

In this mapper method there are three parameters. So in this case it will be necessary to tell the WHERE rendered what parameter name to use the for rendered where clause. That code looks like this:

    Optional<WhereClauseProvider> whereClause = where(id, isLessThan(60))
            .build()
            .render(RenderingStrategies.MYBATIS3, "whereClauseProvider");

    List<AnimalData> animals = whereClause.map(wc -> mapper.selectWithWhereClauseLimitAndOffset(wc, 5, 15)).orElse(Collections.emptyList());

Notice that the string whereClauseProvider is used both as the parameter name in the mapper @Param annotation, and the parameter name in the render method.

The render method also has an override that accepts a TableAliasCalculator and a parameter name.