如何将 Jooq 用于尚不存在的 table?
How to use Jooq for a table that doesn't exist yet?
我有一个带有 Table Cdr 的数据库 (postgresql)。每个月都会在数据库中创建一个新的 table,它与 Table 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: ...from cdr_2017_01 where ("public"."cdr"."field1" = ? and "public"."cdr"."field2" <> ? and "public"."cdr"."field2" <> ?)]; ERROR: missing FROM-clause entry for table "cdr"
我试过使用别名来创建它 'cdr_2017_01 as cdr',但是失败了,因为 cdr 已经存在。好像是因为我用了CDR.FIELD1,还有CDR.fields(),jooq要求from子句中的table是CDR。有什么方法可以使它通用,还是我不应该使用 Jooq 进行这种查询?
错误
您遇到的错误源于您在字段引用中使用了生成的 CDR
文字,例如CDR.FIELD1
。所有这些字段都将使用 "cdr"
table 完全限定,而不是您在 from 子句中输入的 "cdr_2017_01"
table。
您可以打开 debug logging 以查看 jOOQ 生成并发送到服务器的格式化 SQL 字符串。
解决方法
最简单的解决方法是将您的 "cdr_2017_01"
table 别名改回 "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。它正是为这些 multi-tenancy / 分区 use-cases.
设计的
然后您可以按照以下方式写一些东西:
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 的分区功能,在这种情况下,您可能不需要在客户端中明确指定 table 名称:
https://www.postgresql.org/docs/current/static/ddl-partitioning.html
我有一个带有 Table Cdr 的数据库 (postgresql)。每个月都会在数据库中创建一个新的 table,它与 Table 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: ...from cdr_2017_01 where ("public"."cdr"."field1" = ? and "public"."cdr"."field2" <> ? and "public"."cdr"."field2" <> ?)]; ERROR: missing FROM-clause entry for table "cdr"
我试过使用别名来创建它 'cdr_2017_01 as cdr',但是失败了,因为 cdr 已经存在。好像是因为我用了CDR.FIELD1,还有CDR.fields(),jooq要求from子句中的table是CDR。有什么方法可以使它通用,还是我不应该使用 Jooq 进行这种查询?
错误
您遇到的错误源于您在字段引用中使用了生成的 CDR
文字,例如CDR.FIELD1
。所有这些字段都将使用 "cdr"
table 完全限定,而不是您在 from 子句中输入的 "cdr_2017_01"
table。
您可以打开 debug logging 以查看 jOOQ 生成并发送到服务器的格式化 SQL 字符串。
解决方法
最简单的解决方法是将您的 "cdr_2017_01"
table 别名改回 "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。它正是为这些 multi-tenancy / 分区 use-cases.
设计的然后您可以按照以下方式写一些东西:
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 的分区功能,在这种情况下,您可能不需要在客户端中明确指定 table 名称:
https://www.postgresql.org/docs/current/static/ddl-partitioning.html