I recently started working with JooQ and I want to implement the query below, but I was not able to do this.
insert into user_organization_role(id_user, id_organization, id_role,id_workspace)
with cte_0 as(select id_user
, id_organization
, id_role
, id_workspace
from user_organization_role
where id_user = 0)
select distinct ur.id_user
, cte_0.id_organization
, cte_0.id_role
, cte_0.id_workspace
from user_organization_role ur
, cte_0
where ur.id_user <> 0
and (ur.id_user, cte_0.id_organization, cte_0.id_role, cte_0.id_workspace) not in (select id_user, id_organization, id_role, id_workspace from user_organization_role where id_user <> 0)
So far I have reached the next option, but I don't know how to continue and how to make it functional.
userDSLContext.insertInto(Tables.USER_ORGANIZATION_ROLE.asterisk(), DSL.with("cte_0")
.as(DSL.select(Tables.USER_ORGANIZATION_ROLE.asterisk()).from(Tables.USER_ORGANIZATION_ROLE).where(Tables.USER_ORGANIZATION_ROLE.ID_USER.eq(0)))
.selectDistinct(DSL.table(DSL.name("ur")).field("ID_USER"), DSL.table(DSL.name("cte_0")).field("ID_ORGANIZATION"),
DSL.table(DSL.name("cte_0")).field("ID_ROLE"), DSL.table(DSL.name("cte_0")).field("ID_WORKSPACE"))
.from(Tables.USER_ORGANIZATION_ROLE.as("ur"), DSL.table(DSL.name("cte_0"))).where(
DSL.table(DSL.name("cte_0")).field("ID_WORKSPACE").ne(DSL.inline(0)).and(
DSL.table(DSL.name("ur")).field("ID_USER"), DSL.table(DSL.name("cte_0")).field("ID_ORGANIZATION"),
DSL.table(DSL.name("cte_0")).field("ID_ROLE"), DSL.table(DSL.name("cte_0")).field("ID_WORKSPACE")
)
));
Let's look at the individual parts of your query
INSERT
The first problem is your
INSERTstatement. You wrote:But there's no such method in the jOOQ API. Why did you write it this way?
DSLContext.insertInto(Table<?>, ...)accepts a table first, not anorg.jooq.QualifiedAsterisk.You probably used the
asterisk()method, because you thought this would somehow map to inserting into all columns? But you're not usingUSER_ORGANIZATION_ROLE.*as an expression in your SQL query either, so why do this?Why not translate your original query directly:
INSERT .. SELECT
You tried to pass the
Selectexpression directly to theinsertInto()method, but again, the jOOQ API doesn't have any such method that accepts aSelectalong with the table. The example from the manual seems clear?So, translated to your use-case:
At this point, it's also worth noting that every query in jOOQ is a dynamic SQL query, so nothing stops you from assigning parts to local variables if that helps better structure and understand the individual parts of your query.
WITH .. SELECT
That part has a few more issues, including:
table(name("cte_0")).field("ID_ROLE")doesn't work this way. TheTable<?>you're creating this way does not know anything about anID_ROLEfield, so it can't look it up. This is documented in the Javadoc. I.e.You have to use
field(name("cte_0", "ID_ROLE"))insteadData types should be added to your field projections, so you get type safety and the correct projection when you execute the query, i.e. this would be better:
field(name("cte_0", "ID_ROLE"), ID_ROLE.getDataType())There may be other issues
A comment on when to use jOOQ
jOOQ works very well for complex queries, especially when they're dynamic. In some cases, namely when derived tables or CTE are involved, jOOQ can still handle the complexity, but the internal DSL approach makes the SQL statement a bit hard to read / write, mainly because it's not possible to reference a table that has not yet been declared. The whole type safety argument fails with derived tables or CTE when you write static SQL, i.e. non-dynamic SQL.
So, in the jOOQ world, whenever you're using derived tables or CTE, think about:
Rewriting the query to something simpler
Your query seems to be doing the same thing as this?
I don't think you needed the CTE in the first place. This seems exactly equivalent. I'm not quite sure about the use-case. You seem to be operating on a relationship table, and automatically add a relationship to the "default" organization/role/workspace for every user who doesn't have this yet. So, maybe, a classic
INSERT IGNOREwould even be better? I.e. like this?This is assuming that the 4 columns form a
UNIQUEconstraint