Reputation: 1714
I want to perform something like this in SQL:
SELECT
*
FROM
tbl1 t1
INNER JOIN
(SELECT MAX(col1) as maxCol, col2 FROM tbl1 t1 GROUP BY t1.col2) subQ
ON t1.col2 = subQ.col2
AND t1.col1 = subQ.maxCol
In jOOQ, I store the subQ
into Select<?>
object:
Select<?> subQ = myDSL.select(DSL.max(TBL1.COL1).as("maxCol"), TBL1.COL2)
.from(TBL1)
.groupBy(TBL1.COL2);
My question is, how to get the maxCol
column from subQ
and use it in join
? My join
is something like this:
select()
.from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.asTable().field("maxCol")));
I have error on .on()
The method eq(String) in the type Field is not applicable for the arguments (Field)
what should I do?
Upvotes: 5
Views: 3472
Reputation: 220762
If you're using MySQL 8.0+, don't use a subquery but a window function instead. This would be the equivalent query to yours:
SELECT *
FROM (
SELECT t1.*, RANK() OVER (PARTITION BY t1.col2 ORDER BY col1 DESC) rk
FROM tbl1 t1
) t
WHERE t.rk = 1
The advantage is that you only have a single tbl1
access, which is likely to run faster.
If you access a field by untyped name (String
or org.jooq.Name
) from any table, then the compiler does not have any type information to put on the resulting Field<?>
, which is why your original code doesn't compile.
You can, however, use one of the following techniques:
maxCol
field referenceFrom your subquery, factor out the maxCol
field reference and assign it to a local variable (assuming it is of type Integer
, replace if needed):
Field<Integer> maxCol = DSL.max(TBL1.COL1).as("maxCol");
Select<?> subQ = myDSL.select(maxCol, TBL1.COL2).from(TBL1).groupBy(TBL1.COL2);
Now, you can also use this reference to extract a column from the subquery:
Field<Integer> subQMaxCol = subQ.field(maxCol);
Or inline that directly in your solution:
select().from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.field(maxCol)));
maxCol
column after TBL1.COL1
In this particular use-case, it might make sense not to introduce any new names, but to re-use COL1
as a name:
Select<?> subQ = myDSL.select(DSL.max(TBL1.COL1).as(TBL1.COL1), TBL1.COL2)
.from(TBL1)
.groupBy(TBL1.COL2);
In this case (if there is no ambiguous COL1
column name), you can use that reference to extract the COL1
field again from the subquery:
select().from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.field(TBL1.COL1)));
TBL1.COL1
reference's data typeFrom your original solution, just add the data type when you extract the field from the subquery:
select().from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.field("maxCol", TBL1.COL1.getDataType())));
Or, coerce it:
select().from(TBL1)
.join(subQ.asTable())
.on(TBL1.COL1.eq(subQ.field("maxCol").coerce(TBL1.COL1)));
Upvotes: 1
Reputation: 1714
This solve the problem:
select().from(TBL1).join(subQ.asTable()).on(TBL1.COL1.eq((Field<DataType>) subQ.field("maxCol")));
Upvotes: 0