如何将 MYSQL 查询翻译成 JooQ
How to translate a MYSQL query to JooQ
我最近开始使用 JooQ,我想实现下面的查询,但我无法做到。
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)
到目前为止我已经达到了下一个选项,但我不知道如何继续以及如何使其发挥作用。
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")
)
));
让我们看看您查询的各个部分
插入
第一个问题是您的 INSERT
语句。您写道:
insertInto(Tables.USER_ORGANIZATION_ROLE.asterisk(), ...)
但是jOOQ中没有这样的方法API。你为什么这样写? DSLContext.insertInto(Table<?>, ...)
accepts a table first, not an org.jooq.QualifiedAsterisk
.
您可能使用了 asterisk()
方法,因为您认为这会以某种方式映射到插入所有列?但是您也没有在 SQL 查询中使用 USER_ORGANIZATION_ROLE.*
作为表达式,那么为什么要这样做呢?
为什么不直接翻译您的原始查询:
// I'm just going to assume the usual static imports, to reduce "noise"
insertInto(USER_ORGANIZATION_ROLE,
USER_ORGANIZATION_ROLE.ID_USER,
USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
USER_ORGANIZATION_ROLE.ID_ROLE,
USER_ORGANIZATION_ROLE.ID_WORKSPACE)
插入 .. SELECT
您试图将 Select
表达式直接传递给 insertInto()
方法,但是同样,jOOQ API 没有接受 Select
以及 table。 example from the manual seems clear?
create.insertInto(table)
.select(select)
.execute();
所以,翻译成你的use-case:
// The WITH .. SELECT
Select<Record4<.., .., .., ..>> select = ...
// The code from before
insertInto(USER_ORGANIZATION_ROLE,
USER_ORGANIZATION_ROLE.ID_USER,
USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
USER_ORGANIZATION_ROLE.ID_ROLE,
USER_ORGANIZATION_ROLE.ID_WORKSPACE)
// Put your WITH .. SELECT in here
.select(select)
在这一点上,还值得注意的是 jOOQ 中的每个查询都是一个 dynamic SQL query,因此如果这有助于更好地构建和理解查询的各个部分,则没有什么可以阻止您将部分分配给局部变量。
与 .. SELECT
那部分还有一些问题,包括:
table(name("cte_0")).field("ID_ROLE")
这样不行。您以这种方式创建的 Table<?>
对 ID_ROLE
字段一无所知,因此无法查找。 This is documented in the Javadoc。即
The returned table does not know its field references, i.e. Fields.fields() returns an empty array.
您必须改用 field(name("cte_0", "ID_ROLE"))
应将数据类型添加到您的字段投影中,以便在执行查询时获得类型安全和正确的投影,即这样会更好:field(name("cte_0", "ID_ROLE"), ID_ROLE.getDataType())
可能还有其他问题
关于何时使用 jOOQ 的评论
jOOQ 非常适合复杂的查询,尤其是当它们是动态的时候。在某些情况下,即当涉及派生的 tables 或 CTE 时,jOOQ 仍然可以处理复杂性,但内部 DSL 方法使 SQL 语句有点难以读/写,主要是因为它不是可能引用尚未声明的 table。当您编写静态 SQL,即 non-dynamic SQL.
时,整个类型安全参数因派生 tables 或 CTE 而失败
因此,在 jOOQ 世界中,每当您使用派生的 table 或 CTE 时,请考虑:
- 是否可以使用原生 SQL 来处理复杂的部分,例如通过 plain SQL templating 或视图等。(说真的,仅仅因为你正在使用 jOOQ 并不意味着你必须将它用于 每个查询 )
- 您是否可以 re-write 您的查询更简单(无论是否使用 jOOQ 通常都更好)
将查询重写为更简单的内容
您的查询似乎与此相同?
insert into user_organization_role (
id_user, id_organization, id_role, id_workspace
)
select distinct
ur.id_user,
ur0.id_organization,
ur0.id_role,
ur0.id_workspace
from
user_organization_role ur,
user_orgainzation_role ur0
where ur.id_user <> 0
and ur0.id_user = 0
and (ur.id_user, ur0.id_organization, ur0.id_role, ur0.id_workspace) not in (
select id_user, id_organization, id_role, id_workspace
from user_organization_role
where id_user <> 0
)
我不认为你首先需要 CTE。这看起来完全等同。我不太确定 use-case。您似乎在对关系 table 进行操作,并自动为每个还没有此关系的用户添加关系到“默认”organization/role/workspace。那么,也许经典 INSERT IGNORE
会更好? IE。像这样?
insert ignore into user_organization_role (
id_user, id_organization, id_role, id_workspace
)
select distinct
ur.id_user,
ur0.id_organization,
ur0.id_role,
ur0.id_workspace
from
user_organization_role ur,
user_orgainzation_role ur0
where ur.id_user <> 0
and ur0.id_user = 0
这是假设 4 列形成一个 UNIQUE
约束条件
我尝试执行最后一个 SQL 查询,但遇到以下问题
'select(org.jooq.Select<? extends org.jooq.Record3<java.lang.Integer,java.lang.Integer,java.lang.Integer>>)' in 'org.jooq.InsertValuesStep3' cannot be applied to '(org.jooq.Select<org.jooq.Record4<java.lang.Integer,java.lang.Integer,java.lang.Integer,java.lang.Integer>>)'
这是我在阅读上面的全部评论后设法实现的代码
UserOrganizationRole ur = Tables.USER_ORGANIZATION_ROLE;
UserOrganizationRole ur0 = Tables.USER_ORGANIZATION_ROLE;
Select<Record4<Integer, Integer, Integer, Integer>> select = DSL.selectDistinct(ur.ID_USER,ur0.ID_ORGANIZATION,ur0.ID_ROLE,ur0.ID_WORKSPACE)
.from(ur,ur0).where(ur.ID_USER.notEqual(0).and(ur0.ID_USER.eq(0)));
userDSLContext.insertInto(Tables.USER_ORGANIZATION_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
Tables.USER_ORGANIZATION_ROLE.ID_WORKSPACE)
.select(select).execute();
同时,我解决了这个问题。谢谢 Lukas Eder!
UserOrganizationRole ur = Tables.USER_ORGANIZATION_ROLE.as("ur");
UserOrganizationRole ur0 = Tables.USER_ORGANIZATION_ROLE.as("ur0");
Select<Record4<Integer, Integer, Integer, Integer>> select = DSL.selectDistinct(ur.ID_USER, ur0.ID_ORGANIZATION, ur0.ID_ROLE, ur.ID_WORKSPACE)
.from(ur, ur0).where(ur.ID_USER.notEqual(DEFAULT_ID_USER).and(ur0.ID_USER.eq(DEFAULT_ID_USER)));
userDSLContext.insertInto(Tables.USER_ORGANIZATION_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_USER, Tables.USER_ORGANIZATION_ROLE.ID_ORGANIZATION, Tables.USER_ORGANIZATION_ROLE.ID_ROLE,
Tables.USER_ORGANIZATION_ROLE.ID_WORKSPACE)
.select(select)
.onDuplicateKeyIgnore()
.execute();
我最近开始使用 JooQ,我想实现下面的查询,但我无法做到。
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)
到目前为止我已经达到了下一个选项,但我不知道如何继续以及如何使其发挥作用。
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")
)
));
让我们看看您查询的各个部分
插入
第一个问题是您的 INSERT
语句。您写道:
insertInto(Tables.USER_ORGANIZATION_ROLE.asterisk(), ...)
但是jOOQ中没有这样的方法API。你为什么这样写? DSLContext.insertInto(Table<?>, ...)
accepts a table first, not an org.jooq.QualifiedAsterisk
.
您可能使用了 asterisk()
方法,因为您认为这会以某种方式映射到插入所有列?但是您也没有在 SQL 查询中使用 USER_ORGANIZATION_ROLE.*
作为表达式,那么为什么要这样做呢?
为什么不直接翻译您的原始查询:
// I'm just going to assume the usual static imports, to reduce "noise"
insertInto(USER_ORGANIZATION_ROLE,
USER_ORGANIZATION_ROLE.ID_USER,
USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
USER_ORGANIZATION_ROLE.ID_ROLE,
USER_ORGANIZATION_ROLE.ID_WORKSPACE)
插入 .. SELECT
您试图将 Select
表达式直接传递给 insertInto()
方法,但是同样,jOOQ API 没有接受 Select
以及 table。 example from the manual seems clear?
create.insertInto(table)
.select(select)
.execute();
所以,翻译成你的use-case:
// The WITH .. SELECT
Select<Record4<.., .., .., ..>> select = ...
// The code from before
insertInto(USER_ORGANIZATION_ROLE,
USER_ORGANIZATION_ROLE.ID_USER,
USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
USER_ORGANIZATION_ROLE.ID_ROLE,
USER_ORGANIZATION_ROLE.ID_WORKSPACE)
// Put your WITH .. SELECT in here
.select(select)
在这一点上,还值得注意的是 jOOQ 中的每个查询都是一个 dynamic SQL query,因此如果这有助于更好地构建和理解查询的各个部分,则没有什么可以阻止您将部分分配给局部变量。
与 .. SELECT
那部分还有一些问题,包括:
table(name("cte_0")).field("ID_ROLE")
这样不行。您以这种方式创建的Table<?>
对ID_ROLE
字段一无所知,因此无法查找。 This is documented in the Javadoc。即The returned table does not know its field references, i.e. Fields.fields() returns an empty array.
您必须改用
field(name("cte_0", "ID_ROLE"))
应将数据类型添加到您的字段投影中,以便在执行查询时获得类型安全和正确的投影,即这样会更好:
field(name("cte_0", "ID_ROLE"), ID_ROLE.getDataType())
可能还有其他问题
关于何时使用 jOOQ 的评论
jOOQ 非常适合复杂的查询,尤其是当它们是动态的时候。在某些情况下,即当涉及派生的 tables 或 CTE 时,jOOQ 仍然可以处理复杂性,但内部 DSL 方法使 SQL 语句有点难以读/写,主要是因为它不是可能引用尚未声明的 table。当您编写静态 SQL,即 non-dynamic SQL.
时,整个类型安全参数因派生 tables 或 CTE 而失败因此,在 jOOQ 世界中,每当您使用派生的 table 或 CTE 时,请考虑:
- 是否可以使用原生 SQL 来处理复杂的部分,例如通过 plain SQL templating 或视图等。(说真的,仅仅因为你正在使用 jOOQ 并不意味着你必须将它用于 每个查询 )
- 您是否可以 re-write 您的查询更简单(无论是否使用 jOOQ 通常都更好)
将查询重写为更简单的内容
您的查询似乎与此相同?
insert into user_organization_role (
id_user, id_organization, id_role, id_workspace
)
select distinct
ur.id_user,
ur0.id_organization,
ur0.id_role,
ur0.id_workspace
from
user_organization_role ur,
user_orgainzation_role ur0
where ur.id_user <> 0
and ur0.id_user = 0
and (ur.id_user, ur0.id_organization, ur0.id_role, ur0.id_workspace) not in (
select id_user, id_organization, id_role, id_workspace
from user_organization_role
where id_user <> 0
)
我不认为你首先需要 CTE。这看起来完全等同。我不太确定 use-case。您似乎在对关系 table 进行操作,并自动为每个还没有此关系的用户添加关系到“默认”organization/role/workspace。那么,也许经典 INSERT IGNORE
会更好? IE。像这样?
insert ignore into user_organization_role (
id_user, id_organization, id_role, id_workspace
)
select distinct
ur.id_user,
ur0.id_organization,
ur0.id_role,
ur0.id_workspace
from
user_organization_role ur,
user_orgainzation_role ur0
where ur.id_user <> 0
and ur0.id_user = 0
这是假设 4 列形成一个 UNIQUE
约束条件
我尝试执行最后一个 SQL 查询,但遇到以下问题
'select(org.jooq.Select<? extends org.jooq.Record3<java.lang.Integer,java.lang.Integer,java.lang.Integer>>)' in 'org.jooq.InsertValuesStep3' cannot be applied to '(org.jooq.Select<org.jooq.Record4<java.lang.Integer,java.lang.Integer,java.lang.Integer,java.lang.Integer>>)'
这是我在阅读上面的全部评论后设法实现的代码
UserOrganizationRole ur = Tables.USER_ORGANIZATION_ROLE;
UserOrganizationRole ur0 = Tables.USER_ORGANIZATION_ROLE;
Select<Record4<Integer, Integer, Integer, Integer>> select = DSL.selectDistinct(ur.ID_USER,ur0.ID_ORGANIZATION,ur0.ID_ROLE,ur0.ID_WORKSPACE)
.from(ur,ur0).where(ur.ID_USER.notEqual(0).and(ur0.ID_USER.eq(0)));
userDSLContext.insertInto(Tables.USER_ORGANIZATION_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_ORGANIZATION,
Tables.USER_ORGANIZATION_ROLE.ID_WORKSPACE)
.select(select).execute();
同时,我解决了这个问题。谢谢 Lukas Eder!
UserOrganizationRole ur = Tables.USER_ORGANIZATION_ROLE.as("ur");
UserOrganizationRole ur0 = Tables.USER_ORGANIZATION_ROLE.as("ur0");
Select<Record4<Integer, Integer, Integer, Integer>> select = DSL.selectDistinct(ur.ID_USER, ur0.ID_ORGANIZATION, ur0.ID_ROLE, ur.ID_WORKSPACE)
.from(ur, ur0).where(ur.ID_USER.notEqual(DEFAULT_ID_USER).and(ur0.ID_USER.eq(DEFAULT_ID_USER)));
userDSLContext.insertInto(Tables.USER_ORGANIZATION_ROLE, Tables.USER_ORGANIZATION_ROLE.ID_USER, Tables.USER_ORGANIZATION_ROLE.ID_ORGANIZATION, Tables.USER_ORGANIZATION_ROLE.ID_ROLE,
Tables.USER_ORGANIZATION_ROLE.ID_WORKSPACE)
.select(select)
.onDuplicateKeyIgnore()
.execute();