javajooq多表查询

v8wbuo2f  于 2021-07-12  发布在  Java
关注(0)|答案(1)|浏览(405)

我有个问题。
我有以下疑问:

SELECT
    Agents.Owner,
    Orders.*
FROM
    Orders
INNER JOIN Agents ON Agents.id = Orders.agentid
WHERE
    Agents.botstate = 'Active' AND Orders.state = 'Active' AND(
        Orders.status = 'Failed' OR Orders.status = 'Processing' AND Orders.DateTimeInProgressMicro < DATE_SUB(NOW(), INTERVAL 10 SECOND))
    ORDER BY
        Orders.agentid

但现在我需要把它转换成 JOOQ 语言。这就是我想到的:

create.select()
        .from(DSL.table("Orders"))
        .join(DSL.table("Agents"))
        .on(DSL.table("Agents").field("Id").eq(DSL.table("Orders").field("AgentId")))
        .where(DSL.table("Agents").field("botstate").eq("Active")
        .and(DSL.table("Orders").field("state").eq("Active"))
        .and((DSL.table("Orders").field("status").eq("Failed"))
        .or(DSL.table("Orders").field("status").eq("Processing")))).fetch().sortAsc(DSL.table("Orders").field("AgentId"));

现在的第一个问题是,它不喜欢所有的 .eq() 语句,因为它给了我一个错误: Cannot resolve method: eq(Java.lang.String) . 我的第二个问题是,我不知道如何用 JOOQ : Orders.DateTimeInProgressMicro < DATE_SUB(NOW(), INTERVAL 10 SECOND) .
第一个问题是我不能只使用:

.on(Agents.Id).eq(Orders.AgentId)

但我需要为每个表输入:

DSL.table("table_name")

对于每一列:

DSL.field("column_name")

否则它就无法识别我的表和列
我该怎么写这封信 SQLJOOQ 正确的版本或替代方案是,我可以使用正常的sql语句?

tvokkenx

tvokkenx1#

为什么你的代码不起作用? Table.field(String) 不构造窗体的路径表达式 table.field . 它试图取消对已知字段的引用 Table . 如果 Table 没有任何已知字段(例如,在使用 DSL.table(String) ,则没有要取消引用的字段。

正确的普通sql api用法

有两种类型的api允许使用动态sql片段:
用于构造纯sql片段和模板的纯sql api
这个 Name 从标识符构造标识符和jooq类型的api
大多数人只有在无法生成代码(见下文)或jooq缺少对特定于供应商的功能(例如某些内置功能)的支持时才使用这些功能。以下是如何使用以下各项编写查询:
普通sql api
这个api的优点是,您可以使用任意sql片段,包括jooq不知道的特定于供应商的函数调用。有一定的风险会遇到语法错误,sql注入(!),以及简单的数据类型问题,因为除非您显式地告诉jooq,否则jooq不会知道数据类型

// as always, this static import is implied:
import static org.jooq.impl.DSL.*;

然后:

create.select()
      .from("orders") // or table("orders")
      .join("agents") // or table("agents")
      .on(field("agents.id").eq(field("orders.id")))
      .where(field("agents.botstate").eq("Active"))
      .and(field("orders.state").eq("Active"))
      .and(field("orders.status").in("Failed", "Processing"))
      .orderBy(field("orders.agentid"))
      .fetch();

有时,显式地告诉jooq有关数据类型是很有用的,例如在中使用这些表达式时 SELECT ,或在创建绑定变量时:

// Use the default SQLDataType for a Java class
field("agents.id", Integer.class);

// Use an explicit SQLDataType
field("agents.id", SQLDataType.INTEGER);

名称api
这个api允许构造标识符(默认情况下是带引号的,但是您可以配置它,或者使用 unquotedName() ). 如果标识符被引用,则可以避免sql注入风险,但是在大多数方言中,您需要正确区分大小写。

create.select()
      .from(table(name("orders")))
      .join(table(name("agents")))
      .on(field(name("agents", "id")).eq(field(name("orders", "id"))))
      .where(field(name("agents", "botstate")).eq("Active"))
      .and(field(name("orders", "state")).eq("Active"))
      .and(field(name("orders", "status")).in("Failed", "Processing"))
      .orderBy(field(name("orders", "agentid")))
      .fetch();

使用代码生成器

一些用例阻止使用jooq的代码生成器,例如,当使用只有在运行时才知道的动态模式时。在所有其他情况下,强烈建议使用代码生成器。一般来说,使用jooq构建sql语句不仅容易得多,而且不会遇到像这里介绍的那样的问题。
您的查询内容如下:

create.select()
      .from(ORDERS)
      .join(AGENTS)
      .on(AGENTS.ID.eq(ORDERS.ID))
      .where(AGENTS.BOTSTATE.eq("Active"))
      .and(ORDERS.STATE.eq("Active"))
      .and(ORDERS.STATUS.in("Failed", "Processing"))
      .orderBy(ORDERS.AGENTID)
      .fetch();

好处:
所有表和列都由java编译器进行类型检查
可以对模式对象使用ide自动完成
您永远不会遇到sql注入问题或语法错误
一旦重命名列或更改数据类型等,代码就会停止编译。
在获取数据时,您已经知道了数据类型
绑定变量使用正确的类型绑定,而不必显式指定它
请记住,纯sql api和identifier api都是为编译时不知道模式或出于任何其他原因需要动态访问模式元素的情况而构建的。它们是低级api,当代码生成是一种选择时,应该避免使用。

相关问题