3

Im currently using jOOQ to build my SQL (with code generation via the mvn plugin).

Executing the created query is not done by jOOQ though (Using vert.X SqlClient for that).

Lets say I want to select all columns of two tables which share some identical column names. E.g. UserAccount(id,name,...) and Product(id,name,...). When executing the following code

val userTable = USER_ACCOUNT.`as`("u")
val productTable = PRODUCT.`as`("p") 

create().select().from(userTable).join(productTable).on(userTable.ID.eq(productTable.AUTHOR_ID))

the build method query.getSQL(ParamType.NAMED) returns me a query like

SELECT "u"."id", "u"."name", ..., "p"."id", "p"."name", ... FROM ...

The problem here is, the resultset will contain the column id and name twice without the prefix "u." or "p.", so I can't map/parse it correctly.

Is there a way how I can say to jOOQ to alias these columns like the following without any further manual efforts ?

SELECT "u"."id" AS "u.id", "u"."name" AS "u.name", ..., "p"."id" AS "p.id", "p"."name" AS "p.name" ...

Im using the holy Postgres Database :)

EDIT: Current approach would be sth like

val productFields = productTable.fields().map { it.`as`(name("p.${it.name}")) }
val userFields = userTable.fields().map { it.`as`(name("p.${it.name}")) }

create().select(productFields,userFields,...)...

This feels really hacky though

Ahmet K
  • 713
  • 18
  • 42

1 Answers1

3

How to correctly dereference tables from records

You should always use the column references that you passed to the query to dereference values from records in your result. If you didn't pass column references explicitly, then the ones from your generated table via Table.fields() are used.

In your code, that would correspond to:

userTable.NAME
productTable.NAME

So, in a resulting record, do this:

val rec = ...
rec[userTable.NAME]
rec[productTable.NAME]

Using Record.into(Table)

Since you seem to be projecting all the columns (do you really need all of them?) to the generated POJO classes, you can still do this intermediary step if you want:

val rec = ...
val userAccount: UserAccount = rec.into(userTable).into(UserAccount::class.java)
val product: Product = rec.into(productTable).into(Product::class.java)

Because the generated table has all the necessary meta data, it can decide which columns belong to it, and which ones don't. The POJO doesn't have this meta information, which is why it can't disambiguate the duplicate column names.

Using nested records

You can always use nested records directly in SQL as well in order to produce one of these 2 types:

  • Record2<Record[N], Record[N]> (e.g. using DSL.row(table.fields()))
  • Record2<UserAccountRecord, ProductRecord> (e.g using DSL.row(table.fields()).mapping(...), or starting from jOOQ 3.17 directly using a Table<R> as a SelectField<R>)

The second jOOQ 3.17 solution would look like this:

// Using an implicit join here, for convenience
create().select(productTable.userAccount(), productTable)
        .from(productTable)
        .fetch();

The above is using implicit joins, for additional convenience

Auto aliasing all columns

There are a ton of flavours that users could like to have when "auto-aliasing" columns in SQL. Any solution offered by jOOQ would be no better than the one you've already found, so if you still want to auto-alias all columns, then just do what you did.

But usually, the desire to auto-alias is a derived feature request from a misunderstanding of what's the best approch to do something in jOOQ (see above options), so ideally, you don't follow down the auto-aliasing road.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Thank you very much for your answer! But if I'm understanding it correctly, these approaches only work when I also use the underlying `fetch` methods correct ? Like I mentioned before, the fetching of the results/records will not be in jOOQ. I'll have to parse them through Vert.X Row class. So it looks like the custom aliasing is the only way for my case. Can you predict some serious troubles with it? – Ahmet K Jun 20 '22 at 23:45
  • @AhmetKazaman: I see. I overlooked that. Probably worth tagging your question accordingly and showing a complete code example, then, so it will be obvious to future visitors of this question – Lukas Eder Jun 21 '22 at 06:22
  • So I guess you indirectly agreed that it is the only possible option in that case :) Yes your right, I'll update the question accordingly. Sry about that – Ahmet K Jun 21 '22 at 19:46
  • @AhmetKazaman: Not necessarily. You could try this third party contribution, instead of binding jOOQ queries to vert.x's SQL client yourself: https://github.com/jklingsporn/vertx-jooq. Or you could use jOOQ's native reactive support via R2DBC. – Lukas Eder Jun 21 '22 at 20:44