简体   繁体   English

jOOQ-使用嵌套子查询联接

[英]jOOQ - join with nested subquery

Let's say I want to find out who wrote CLRS in a book db (tables BOOK , AUTHOR with a junction table BOOK_AUTHOR ). 假设我想找出谁在书db中写了CLRS (表BOOK ,具有连接表BOOK_AUTHOR AUTHOR )。

SelectConditionStep<Record1<String>> query = create
        .select(AUTHOR.LASTNAME.as("AuthorName"))
            .from(
                    (
                            BOOK.leftOuterJoin(BOOK_AUTHOR).on(BOOK.ID.eq(BOOK_AUTHOR.BOOKID))
                    ).leftOuterJoin(AUTHOR).on(AUTHOR.ID.eq(BOOK_AUTHOR.AUTHORID))
            )
            .where(BOOK.TITLE.eq(CLRS_title))
        ;

A bit inefficient to match the entire table, just to select a single book. 匹配整个桌子效率低下,仅选择一本书。 I now want to select that book prior to the match. 我现在想在比赛之前选择那本书。

The jOOQ doc on this matter led me to believe that could look something like this: 关于此事的jOOQ文档使我相信它看起来可能像这样:

Table<Record1<Integer>> clrs = create
        .select(BOOK.ID.as("bookID"))
            .from(BOOK)
            .where(BOOK.TITLE.eq(CLRS_title))

        .asTable()
        ;

SelectJoinStep<Record1<String>> query = create
        .select(AUTHOR.LASTNAME.as("AuthorName"))
            .from(
                    (
                            clrs.leftOuterJoin(BOOK_AUTHOR).on(clrs.field("bookID").eq(BOOK_AUTHOR.BOOKID))
                    ).leftOuterJoin(AUTHOR).on(AUTHOR.ID.eq(BOOK_AUTHOR.AUTHORID))
            )
        ;

However, that fails to compile because 但是,由于无法编译,因此

Cannot resolve method 'eq(org.jooq.TableField<ch.cypherk.bookdb.public_.tables.records.BookAuthorRecord,java.lang.Integer>)'

in the join condition. 在加入条件下。

What's the correct way to write this join? 编写此联接的正确方法是什么?

The problem you're having 您遇到的问题

You're dereferencing a column from your derived table using Table.field(String) : 您正在使用Table.field(String)从派生表中取消引用列:

clrs.field("bookID")

The type you're getting back is Field<?> , with a wildcard. 您返回的类型是Field<?> ,带通配符。 Like with any generic type, once you have a wild card, a lot of operations (but not all) will no longer be possible on that type. 与任何通用类型一样,一旦有了通配符,该类型就将无法进行很多操作(但不是全部)。 Take List<?> , for example. List<?>为例。 You can still call List<?>.get() to retrieve an Object , but not List<?>.add(? element) . 您仍然可以调用List<?>.get()来检索Object ,但不能调用List<?>.add(? element) In Field<?> , you can no longer call eq() , unless you cast the argument to a raw type. Field<?> ,您不能再调用eq() ,除非将参数强制转换为原始类型。

You can also coerce your field's <T> type to the type you already know, eg by using Table.field(String, DataType<T>) 您也可以将字段的<T>类型强制为已知的类型,例如,通过使用Table.field(String, DataType<T>)

clrs.field("bookID", BOOK.ID.getDataType())

Study your various options and you might discover the one(s) you might find most useful 研究您的各种选择,您可能会发现最有用的选择

A better solution to your query 更好的查询解决方案

You don't really need to 你真的不需要

  1. Assign your subquery to a local variable 将您的子查询分配给局部变量
  2. Use a derived table for your problem 使用派生表解决您的问题

Often with jOOQ, if you're having issues with derived tables as above, ask yourself is there really not an easier query I could write instead? 经常与jOOQ一起使用,如果您在使用上述派生表时遇到问题,请问自己是否真的没有一个我可以编写的更简单的查询?

What you really need here is a semi join . 您真正需要的是半连接 Write: 写:

// Assuming this static import
import static org.jooq.impl.DSL.*;

ctx.select(AUTHOR.LASTNAME)
   .from(AUTHOR)
   .where(AUTHOR.ID.in(
        select(BOOK_AUTHOR.AUTHORID)
       .from(BOOK_AUTHOR)
       .join(BOOK).on(BOOK.ID.eq(BOOK_AUTHOR.BOOKID))
       .where(BOOK.TITLE.eq(clrsTitle))
   )
   .fetch();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM