在DoytoQuery中怎么表达select * from t where id = ? or (name = ? and age = ?)

70 阅读2分钟

首先我们得理解一个新的观点:WHERE子句并不是平铺的,而是有层级的。其中,使用AND连接的查询条件是一个层级,使用OR连接的查询条件是一个层级,每一层级的条件都只能使用同一种连接符进行连接。一般情况下,多个查询条件是用AND连接的,于是默认AND作为第一层级,那么标题中的查询语句里,OR连接的两个条件就是第二层级,OR语句的第二个条件里用AND连接的两个条件就是第三层级。

使用JSON表示这样的层级结构看起来可能会清楚点:

{
  "userOr": {
    "id": 5,
    "userAnd": {
      "name": "John",
      "age": 30
    }
  }
}

把这条数据转换为WHERE子句时可以通过键名称的后缀Or和And来确定多个子查询条件的逻辑连接符。 第一层级只有一个键userOr,可以省掉AND连接;userOr下的多个查询条件使用OR进行连接;第一个键对应条件为id=5;第二个键的多个查询条件使用AND进行连接,于是把name="John"和age=30用AND连起来;再把这个条件加上括号和id=5用OR连起来,就得到对应的查询子句:id = 5 OR (name = "John" AND age = 30)。在构造查询条件的时候可以把参数替换为占位符。

然后我们尝试使用代码来构造这样一条JSON数据:

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserQuery {
  private Integer id;
  private String name;
  private Integer age;
  private UserQuery userOr;
  private UserQuery userAnd;

  public static void main(String[] args) throws Exception {
    UserQuery userOr = UserQuery.builder().id(5).userAnd(UserQuery.builder().name("John").age(30).build()).build();
    UserQuery userQuery = UserQuery.builder().userOr(userOr).build();

    ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
    System.out.println(objectMapper.writeValueAsString(userQuery));
    //{"userOr":{"id":5,"userAnd":{"name":"John","age":30}}}
  }
}

这样写除了麻烦点,还是可以构造出同样的JSON数据的,那么就意味着我们可以构造出同样的查询子句了。而且进一步我们会发现,这个查询条件既然能用JSON格式表示出来,那就意味着只要是支持JSON的编程语言都可以构造这样的查询条件。下一步我们就可以尝试使用不同编程语言来实现这种方案。