如何在 jOOQ 中表示自连接?
How does one represent a self-join in jOOQ?
我有以下架构 (SQLite) 用于捕获来自 Messenger 的消息:
create table if not exists spot_message
(
id unsigned big int primary key not null,
messenger_id text not null,
messenger_name text not null,
message_type text not null,
timestamp text not null,
latitude real not null,
longitude real not null
);
我使用以下自连接来查找每个发件人的最新消息:
select t1.*
from spot_message t1
join (select messenger_id, max(timestamp) timestamp
from spot_message
group by messenger_id) t2 on t1.messenger_id = t2.messenger_id and t1.timestamp = t2.timestamp;
我不清楚如何在 jOOQ 中表示它。
我目前有:
DSL.using(c.get())
.select(asterisk())
.from(table("spot_message").as("t1"))
.join(select(field("messenger_id"), max(field("timestamp"))).from(table("spot_message"))
.groupBy(field("messenger_id")))
.on(field("messenger_id")
.eq(field("messenger_id"))
.and(field("timestamp")
.eq(field("timestamp"))));
但不清楚我如何表达加入table(“t2”)的table名称的“as”。
回答您的问题
要将 Select
作为派生 table 的别名,您可以使用:
您正在使用 plain SQL API 构建查询,因此您可以在字符串中使用任何 SQL 表达式,例如"t2.messenger_id"
。这应该有效:
DSL.using(c.get())
.select(asterisk())
.from(table("spot_message").as("t1"))
.join(select(field("messenger_id"), max(field("timestamp")))
.from(table("spot_message"))
.groupBy(field("messenger_id")).asTable("t2")) // t2 alias here
.on(field("t1.messenger_id") // Qualifications here, and below
.eq(field("t2.messenger_id"))
.and(field("t1.timestamp")
.eq(field("t2.timestamp"))));
但是,如果您是 using code generation, which I recommend for various reasons
,这会更具可读性
SpotMessage t1 = SPOT_MESSAGE.as("t1");
SpotMessage t2 = SPOT_MESSAGE.as("t2");
DSL.using(c.get())
.select(t1.asterisk())
.from(t1)
.join(
select(t2.MESSENGER_ID, max(t2.TIMESTAMP).as(t2.TIMESTAMP))
.from(t2)
.groupBy(t2.MESSENGER_ID).asTable(t2))
.on(t1.MESSENGER_ID.eq(t2.MESSENGER_ID))
.and(t1.TIMESTAMP.eq(t2.TIMESTAMP));
使用 window 函数的替代方法
由于您使用的是 SQLite,它支持 window functions, why not just use those? You can even use the QUALIFY
syntax,如果您使用的是商业发行版,jOOQ 可以为您模拟:
在SQL中:
select *
from spot_message
qualify timestamp = max(timestamp) over (partition by messenger_id)
在 jOOQ 中:
ctx.selectFrom(SPOT_MESSAGE)
.qualify(SPOT_MESSAGE.TIMESTAMP.eq(
max(SPOT_MESSAGE.TIMESTAMP).over(partitionBy(SPOT_MESSAGE.MESSENGER_ID))
));
如果 QUALIFY
对您不可用,您仍然可以通过将查询包装在派生的 table:
中手动模拟它
SELECT *
FROM (
SELECT
spot_message.*,
timestamp = max(timestamp) over (partition by messenger_id) AS is_max
FROM spot_message
) AS t
WHERE is_max
我有以下架构 (SQLite) 用于捕获来自 Messenger 的消息:
create table if not exists spot_message
(
id unsigned big int primary key not null,
messenger_id text not null,
messenger_name text not null,
message_type text not null,
timestamp text not null,
latitude real not null,
longitude real not null
);
我使用以下自连接来查找每个发件人的最新消息:
select t1.*
from spot_message t1
join (select messenger_id, max(timestamp) timestamp
from spot_message
group by messenger_id) t2 on t1.messenger_id = t2.messenger_id and t1.timestamp = t2.timestamp;
我不清楚如何在 jOOQ 中表示它。
我目前有:
DSL.using(c.get())
.select(asterisk())
.from(table("spot_message").as("t1"))
.join(select(field("messenger_id"), max(field("timestamp"))).from(table("spot_message"))
.groupBy(field("messenger_id")))
.on(field("messenger_id")
.eq(field("messenger_id"))
.and(field("timestamp")
.eq(field("timestamp"))));
但不清楚我如何表达加入table(“t2”)的table名称的“as”。
回答您的问题
要将 Select
作为派生 table 的别名,您可以使用:
您正在使用 plain SQL API 构建查询,因此您可以在字符串中使用任何 SQL 表达式,例如"t2.messenger_id"
。这应该有效:
DSL.using(c.get())
.select(asterisk())
.from(table("spot_message").as("t1"))
.join(select(field("messenger_id"), max(field("timestamp")))
.from(table("spot_message"))
.groupBy(field("messenger_id")).asTable("t2")) // t2 alias here
.on(field("t1.messenger_id") // Qualifications here, and below
.eq(field("t2.messenger_id"))
.and(field("t1.timestamp")
.eq(field("t2.timestamp"))));
但是,如果您是 using code generation, which I recommend for various reasons
,这会更具可读性SpotMessage t1 = SPOT_MESSAGE.as("t1");
SpotMessage t2 = SPOT_MESSAGE.as("t2");
DSL.using(c.get())
.select(t1.asterisk())
.from(t1)
.join(
select(t2.MESSENGER_ID, max(t2.TIMESTAMP).as(t2.TIMESTAMP))
.from(t2)
.groupBy(t2.MESSENGER_ID).asTable(t2))
.on(t1.MESSENGER_ID.eq(t2.MESSENGER_ID))
.and(t1.TIMESTAMP.eq(t2.TIMESTAMP));
使用 window 函数的替代方法
由于您使用的是 SQLite,它支持 window functions, why not just use those? You can even use the QUALIFY
syntax,如果您使用的是商业发行版,jOOQ 可以为您模拟:
在SQL中:
select *
from spot_message
qualify timestamp = max(timestamp) over (partition by messenger_id)
在 jOOQ 中:
ctx.selectFrom(SPOT_MESSAGE)
.qualify(SPOT_MESSAGE.TIMESTAMP.eq(
max(SPOT_MESSAGE.TIMESTAMP).over(partitionBy(SPOT_MESSAGE.MESSENGER_ID))
));
如果 QUALIFY
对您不可用,您仍然可以通过将查询包装在派生的 table:
SELECT *
FROM (
SELECT
spot_message.*,
timestamp = max(timestamp) over (partition by messenger_id) AS is_max
FROM spot_message
) AS t
WHERE is_max