嵌套记录
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
DSL.row()
构造函数不仅适用于不同类型的 行值表达式谓词,而且还适用于投影嵌套记录类型,在大多数情况下甚至是 Record1 到 Record22 类型,这些类型保持列级别的类型安全。
所有 org.jooq.Row1
到 org.jooq.Row22
类型以及 org.jooq.RowN
类型都扩展了 org.jooq.SelectField
,这意味着它们可以放置在 SELECT 子句 或 RETURNING 子句 中。 SelectField<T>
中的 T
类型变量绑定到相应的 Record1 到 Record22 类型,这使得可以轻松地投影嵌套记录。
SELECT ID, ROW( FIRST_NAME, LAST_NAME ) FROM AUTHOR
// Type inference via lambdas or var really shines here! Result<Record2<Integer, Record2<String, String>>> result = create.select( AUTHOR.ID, row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)) .from(AUTHOR) .fetch();
将嵌套记录与数组组合
如果您的 RDBMS 支持 ARRAY
类型和 ARRAY
构造函数,并且本地支持嵌套记录,那么您很可能可以将这两个特性结合起来。 例如,要查找作者的所有书籍,作为嵌套集合而不是平面 join
SELECT ID, ROW( AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME ), ARRAY( SELECT BOOK.ID, BOOK.TITLE FROM BOOK WHERE BOOK.AUTHOR_ID = AUTHOR.ID ) FROM AUTHOR
// Type inference via lambdas or var really shines here! Result<Record3< Integer, Record2<String, String>, Record2<Integer, String>[] >> result = create.select( AUTHOR.ID, row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) array( select(row(BOOK.ID, BOOK.TITLE)) .from(BOOK) .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) ) ) .from(AUTHOR) .fetch();
将 RecordMapper 附加到嵌套记录
嵌套记录有助于使用结构类型组织结果集,但是当您将 RecordMapper
附加到它们时,它们才会真正发挥作用。 RecordMapper 是一个 java.lang.FunctionalInterface
,可以将 Record
子类型转换为任何用户类型 E
。 通过调用例如 Row2.mapping()
,您可以将 ad-hoc 转换器 附加到嵌套记录类型,将嵌套对象转换为更有意义的内容。
// Especially useful using Java 16 record types! record Name(String firstName, String lastName) {} record Author(int id, Name name) {} // The "scary" structural type has gone! List<Author> authors = create.select( AUTHOR.ID, row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new) ) .from(AUTHOR) .fetch(Records.mapping(Author::new));
以上所有操作都是类型安全的,并且不使用反射! 亲自尝试一下 - 向查询或记录添加或删除列,并观察出现的编译错误。
现在是 ARRAY
示例
record Name(String firstName, String lastName) {} record Book(int id, String title) {} record Author(int id, Name name, Book[] books) {} // Again, no structural typing here has gone! List<Author> authors = create.select( AUTHOR.ID, row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new), array( select(row(BOOK.ID, BOOK.TITLE).mapping(Book.class, Book::new) .from(BOOK) .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) ) ) .from(AUTHOR) .fetch(Records.mapping(Author::new));
同样,一切都是类型安全的。 不幸的是,在这种情况下需要反射来构造 Book[]
数组。 您必须传递 Book.class
引用以帮助 jOOQ。 如果您喜欢列表,没问题。 您可以使用相同的技术再次包装数组,使用显式 ad-hoc 转换器
record Name(String firstName, String lastName) {} record Book(int id, String title) {} record Author(int id, Name name, List<Book> books) {} // Is now using a List<Book> instead of Book[] // Again, no structural typing here has gone! List<Author> authors = create.select( AUTHOR.ID, row(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME).mapping(Name::new), array( select(row(BOOK.ID, BOOK.TITLE).mapping(Book.class, Book::new) .from(BOOK) .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) ).convertFrom(Arrays::asList) // Additional converter here ) .from(AUTHOR) .fetch(Records.mapping(Author::new));
方言支持
此示例使用 jOOQ
select(row(BOOK.ID, BOOK.TITLE))
翻译成以下特定方言的表达式
访问
SELECT BOOK.ID [nested__ID], BOOK.TITLE [nested__TITLE] FROM ( SELECT count(*) dual FROM MSysResources ) AS dual
ASE, SQLDataWarehouse, SQLServer
SELECT BOOK.ID [nested__ID], BOOK.TITLE [nested__TITLE]
Aurora MySQL, MemSQL
SELECT BOOK.ID `nested__ID`, BOOK.TITLE `nested__TITLE` FROM DUAL
Aurora Postgres, CockroachDB, DuckDB, H2, Postgres, YugabyteDB
SELECT ROW (BOOK.ID, BOOK.TITLE) nested
BigQuery, MariaDB, MySQL, SQLite
SELECT BOOK.ID `nested__ID`, BOOK.TITLE `nested__TITLE`
ClickHouse
SELECT TUPLE (BOOK.ID, BOOK.TITLE) nested
Databricks
SELECT ( coalesce(BOOK.ID), coalesce(BOOK.TITLE) ) nested
DB2
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM SYSIBM.DUAL
Derby
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM SYSIBM.SYSDUMMY1
Exasol, Oracle, Redshift, Snowflake, Trino, Vertica
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE"
Firebird
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM RDB$DATABASE
Hana
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM SYS.DUMMY
HSQLDB
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM (VALUES (1)) AS dual (dual)
Informix
SELECT ROW (BOOK.ID, BOOK.TITLE) nested FROM ( SELECT 1 AS dual FROM systables WHERE (tabid = 1) ) AS dual
Sybase
SELECT BOOK.ID [nested__ID], BOOK.TITLE [nested__TITLE] FROM SYS.DUMMY
Teradata
SELECT BOOK.ID "nested__ID", BOOK.TITLE "nested__TITLE" FROM ( SELECT 1 AS "dual" ) AS "dual"
使用 jOOQ 3.21 生成。早期 jOOQ 版本的支持可能有所不同。 在我们的网站上翻译您自己的 SQL
反馈
您对此页面有任何反馈吗? 我们很乐意倾听!