Reputation: 92
I have a database (postgresql) with a Table Cdr. Every month a new table is created in the database that has the same schema as Table Cdr, named Cdr__ (eg. Cdr_2016_04).
I'm trying to use Jooq to query the database, based on a date provided. The trouble is that:
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);
doesn't work because it indicates that
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"
I've tried using an alias to make it 'cdr_2017_01 as cdr', but that fails because cdr already exists. It seems that because I use CDR.FIELD1, and CDR.fields(), jooq requires that the table in the from clause be CDR. Is there some way to make this generic, or should I not be using Jooq for this kind of query?
Upvotes: 2
Views: 1966
Reputation: 220877
The error you're getting originates from your usage of the generated CDR
literal in your field references, e.g. CDR.FIELD1
. All these fields will be fully qualified with the "cdr"
table, not the "cdr_2017_01"
table that you put in the from clause.
You can turn on debug logging to see formatted SQL strings that jOOQ generates and sends to the server.
The simplest workaround is to alias your "cdr_2017_01"
table back to "cdr"
like this:
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);
This will work to some extent with most queries.
You should use the runtime schema / table mapping feature for this. It is designed exactly for these kinds of multi-tenancy / partitioning use-cases.
You can then write something along the lines of:
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);
Another option, of course, might be to use PostgreSQL's partitioning feature, in case of which you might not need to explicitly specify table names in the client:
https://www.postgresql.org/docs/current/static/ddl-partitioning.html
Upvotes: 1