如何将Jooq用于尚不存在的表?

时间:2017-02-14 21:13:12

标签: java jooq

我有一个带有表Cdr的数据库(postgresql)。每个月都会在数据库中创建一个与表Cdr具有相同模式的新表,名为Cdr__(例如Cdr_2016_04)。

我正在尝试使用Jooq根据提供的日期查询数据库。麻烦的是:

context.select(CDR.fields())
            .from("cdr_2017_01")
            .where(CDR.FIELD1.eq("somevalue")
                .and(CDR.FIELD2.notEqual("value 2")
                .and(CDR.FIELD2.notEqual("value 3")))
            .fetchInto(Cdr.class);

不起作用,因为它表示

  

org.jooq.exception.DataAccessException:...来自cdr_2017_01其中(“public”。“cdr”。“field1”=?和“public”。“cdr”。“field2”<>?和“ public“。”cdr“。”field2“<>?)];错误:缺少表“cdr”

的FROM子句条目

我尝试使用别名使其'cdr_2017_01 as cdr',但由于cdr已经存在而失败。似乎因为我使用CDR.FIELD1和CDR.fields(),jooq要求from子句中的表是CDR。有没有办法使这个通用,或者我不应该使用Jooq进行这种查询?

1 个答案:

答案 0 :(得分:1)

错误

您获得的错误源自您在字段引用中使用生成的CDR字面值,例如: CDR.FIELD1。所有这些字段都将使用"cdr"表完全限定,而不是您在from子句中放入的"cdr_2017_01"表。

您可以打开debug logging以查看jOOQ生成并发送到服务器的格式化SQL字符串。

解决方法

最简单的解决方法是将"cdr_2017_01"表格替换为"cdr",如下所示:

context.select(CDR.fields())
        .from("cdr_2017_01 as cdr")
        .where(CDR.FIELD1.eq("somevalue")
            .and(CDR.FIELD2.notEqual("value 2")
            .and(CDR.FIELD2.notEqual("value 3")))
        .fetchInto(Cdr.class);

这在一定程度上适用于大多数查询。

更好的解决方案

您应该使用runtime schema / table mapping feature。它专为这些多租户/分区用例而设计。

然后你可以写下以下内容:

DSL.using(connection, new Settings()
       .withRenderMapping(new RenderMapping()
           .withSchemata(new MappedSchema()
               .withInput("my_schema_name")
               .withTables(new MappedTable()
                   .withInput(CDR.getName())
                   .withOutput(CDR.getName() + "_2017_01")))))
   .select(CDR.fields())
   .from(CDR)
   .where(CDR.FIELD1.eq("somevalue")
       .and(CDR.FIELD2.notEqual("value 2")
       .and(CDR.FIELD2.notEqual("value 3")))
   .fetchInto(Cdr.class);

当然,另一个选择可能是使用PostgreSQL的分区功能,如果您可能不需要在客户端中明确指定表名:

https://www.postgresql.org/docs/current/static/ddl-partitioning.html