如何在 jOOQ 中转换 "to_json()" PostgreSQL 函数?
How to convert "to_json()" PostgreSQL function in jOOQ?
我正在尝试将以下 PostgreSQL 查询转换为 jOOQ,但似乎找不到解决此问题的适当方法。这是查询:
SELECT b.book_id AS b_id, b.title, b.price, b.amount, b.is_deleted,
to_json(array_agg(DISTINCT aut.*)) as authors,
to_json(array_agg(DISTINCT cat.*)) as categories
FROM book b
LEFT JOIN author_book AS ab ON b.book_id = ab.book_id
LEFT JOIN author AS aut ON ab.author_id = aut.author_id
LEFT JOIN category_book AS cb ON b.book_id = cb.book_id
LEFT JOIN category AS cat ON cb.category_id = cat.category_id
GROUP BY b_id ORDER BY b_id ASC;
到目前为止,这是我在 jOOQ 中想到的:
dslContext
.select(BOOK.BOOK_ID, BOOK.TITLE, BOOK.PRICE, BOOK.AMOUNT, BOOK.IS_DELETED,
DSL.val(DSL.jsonArray(DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID),
DSL.arrayAggDistinct(AUTHOR.FIRST_NAME),
DSL.arrayAggDistinct(AUTHOR.LAST_NAME))
).cast(SQLDataType.JSON),
DSL.val(DSL.jsonArray(DSL.arrayAggDistinct(CATEGORY.CATEGORY_ID),
DSL.arrayAggDistinct(CATEGORY.NAME),
DSL.arrayAggDistinct(CATEGORY.IS_DELETED))
).cast(SQLDataType.JSON)
).from(BOOK
.leftJoin(AUTHOR_BOOK).on(BOOK.BOOK_ID.eq(AUTHOR_BOOK.BOOK_ID))
.leftJoin(AUTHOR).on(AUTHOR_BOOK.AUTHOR_ID.eq(AUTHOR.AUTHOR_ID))
.leftJoin(CATEGORY_BOOK).on(BOOK.BOOK_ID.eq(CATEGORY_BOOK.BOOK_ID))
.leftJoin(CATEGORY).on(CATEGORY_BOOK.CATEGORY_ID.eq(CATEGORY.CATEGORY_ID))
).where(AUTHOR.AUTHOR_ID.eq(Long.valueOf(authorId))
).groupBy(BOOK.BOOK_ID).orderBy(BOOK.BOOK_ID.asc())
当我执行 jOOQ 代码时,出现以下异常:
Type class org.jooq.impl.JSONArray is not supported in dialect DEFAULT
我用谷歌搜索了这个异常,在 问题中只发现了这个类似的异常。是否有任何适当的解决方法来解决 PostgreSQL to_json
函数的这种转换和 array_agg() 的组合,它在给定的 aut(hor)/cat(egory) [=45= 的所有字段上保持 DISTINCT ]?
更新:
这是我以前在 jOOQ 中以非类型安全方式编写查询的另一种方式:
dslContext.resultQuery(DBQueries.GET_ALL_BOOKS_BY_AUTHOR_ID, Long.valueOf(authorId)));
...这里是 DBQueries.GET_ALL_BOOKS_BY_AUTHOR_ID
变量的代码:
public class DBQueries {
//...
static String GET_ALL_BOOKS_BY_AUTHOR_ID = "SELECT b.book_id AS b_id, b.title, b.price, b.amount, b.is_deleted, " +
"to_json(array_agg(DISTINCT aut.*)) as authors, to_json(array_agg(DISTINCT cat.*)) as categories " +
"FROM book b " +
"LEFT JOIN author_book AS ab ON b.book_id = ab.book_id " +
"LEFT JOIN author AS aut ON ab.author_id = aut.author_id " +
"LEFT JOIN category_book AS cb ON b.book_id = cb.book_id " +
"LEFT JOIN category AS cat ON cb.category_id = cat.category_id " +
"WHERE aut.author_id = :id " +
"GROUP BY b_id ORDER BY b_id ASC;";
}
顺便说一句,我已经更新了我的问题,以明确我是如何使用 resultQuery() 方法来实现我想要的。我在问如何在 jOOQ 中以尽可能多的类型安全方式实现这一点,因为我有更复杂的查询,我不知道是否可以通过不使用 PostgreSQL to_json()
函数来实现。例如,我想在 jOOQ 中创建类似 this 的内容,例如在 bytefish.de 网站提交的 link 的“04_create_functions.sql”部分。
get_image
--------------------------------------------------------------
{"imageid" : 1,
"hash" : "a3b0c44",
"description" : "Some Description",
"created_on" : "2015-03-09T22:00:45.111",
"comments" : [{"commentid":1, "imageid":1, "text":"Awesome!", "createdon":"2015-03-09T22:58:47.783"},
{"commentid":2, "imageid":1, "text":"This is just a second comment.", "createdon" : "2015-03-09T22:58:47.783"}],
"tags" : [{"tagid":1,"name":"Cool"},
{"tagid":2,"name":"Berlin"}]}
(1 row)
我正在尝试为 (book) ORDERS 的 REPORT 做同样的事情,其中涉及 8 tables 的查询(我没有 post 这里的查询试图解决 jOOQ 中更简单的问题,即创建 JsonArray)。
您的具体错误
- 您将
Field
表达式 (DSL.jsonArray()
) 包装在 DSL.val()
中,这意味着绑定值。那是行不通的,是您异常的原因
- 但是,您还不能通过以这种方式将普通数组包装成
JSON
数组。 jOOQ 不知道你的意思是在幕后调用 to_json
。从 jOOQ 3.13 开始,您将不得不求助于使用一些 plain SQL templating(请参见下面的示例),或者您获取一个数组而不将其转换为 JSON 在您的 SQL 逻辑中,并且仅在您的 Java 客户端逻辑中将其转换为 JSON。
普通 SQL 模板示例:
DSL.field("to_json({0})", JSON.class, DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID))
jOOQ 3.14 JSON 支持
请注意,jOOQ 3.14 将通过标准 SQL JSON API 和 SQL 服务器的 FOR JSON
子句:
JSON_ARRAY
, JSON_OBJECT
, JSON_VALUE
function support
JSON_ARRAYAGG
support
JSON_OBJECTAGG
support
JSON_TABLE
table valued function support
JSON_EXISTS
predicate support
并且:
正如@Lukas_Eder 指出要解决此问题,需要通过普通 SQL 模板创建 JSON 对象,如下例所示:
DSL.field("to_json({0})", JSON.class, DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID))
我在文档中阅读了更多关于上述方法的内容,并了解了如何根据自己的需要修改方法(以便与 PostgreSQL 语法中有问题的方法相等):
DSL.field( "to_json(array_agg(DISTINCT author.*))", JSON.class, DSL.arrayAgg(AUTHOR.AUTHOR_ID) ).as("authors")
我正在尝试将以下 PostgreSQL 查询转换为 jOOQ,但似乎找不到解决此问题的适当方法。这是查询:
SELECT b.book_id AS b_id, b.title, b.price, b.amount, b.is_deleted,
to_json(array_agg(DISTINCT aut.*)) as authors,
to_json(array_agg(DISTINCT cat.*)) as categories
FROM book b
LEFT JOIN author_book AS ab ON b.book_id = ab.book_id
LEFT JOIN author AS aut ON ab.author_id = aut.author_id
LEFT JOIN category_book AS cb ON b.book_id = cb.book_id
LEFT JOIN category AS cat ON cb.category_id = cat.category_id
GROUP BY b_id ORDER BY b_id ASC;
到目前为止,这是我在 jOOQ 中想到的:
dslContext
.select(BOOK.BOOK_ID, BOOK.TITLE, BOOK.PRICE, BOOK.AMOUNT, BOOK.IS_DELETED,
DSL.val(DSL.jsonArray(DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID),
DSL.arrayAggDistinct(AUTHOR.FIRST_NAME),
DSL.arrayAggDistinct(AUTHOR.LAST_NAME))
).cast(SQLDataType.JSON),
DSL.val(DSL.jsonArray(DSL.arrayAggDistinct(CATEGORY.CATEGORY_ID),
DSL.arrayAggDistinct(CATEGORY.NAME),
DSL.arrayAggDistinct(CATEGORY.IS_DELETED))
).cast(SQLDataType.JSON)
).from(BOOK
.leftJoin(AUTHOR_BOOK).on(BOOK.BOOK_ID.eq(AUTHOR_BOOK.BOOK_ID))
.leftJoin(AUTHOR).on(AUTHOR_BOOK.AUTHOR_ID.eq(AUTHOR.AUTHOR_ID))
.leftJoin(CATEGORY_BOOK).on(BOOK.BOOK_ID.eq(CATEGORY_BOOK.BOOK_ID))
.leftJoin(CATEGORY).on(CATEGORY_BOOK.CATEGORY_ID.eq(CATEGORY.CATEGORY_ID))
).where(AUTHOR.AUTHOR_ID.eq(Long.valueOf(authorId))
).groupBy(BOOK.BOOK_ID).orderBy(BOOK.BOOK_ID.asc())
当我执行 jOOQ 代码时,出现以下异常:
Type class org.jooq.impl.JSONArray is not supported in dialect DEFAULT
我用谷歌搜索了这个异常,在 to_json
函数的这种转换和 array_agg() 的组合,它在给定的 aut(hor)/cat(egory) [=45= 的所有字段上保持 DISTINCT ]?
更新: 这是我以前在 jOOQ 中以非类型安全方式编写查询的另一种方式:
dslContext.resultQuery(DBQueries.GET_ALL_BOOKS_BY_AUTHOR_ID, Long.valueOf(authorId)));
...这里是 DBQueries.GET_ALL_BOOKS_BY_AUTHOR_ID
变量的代码:
public class DBQueries {
//...
static String GET_ALL_BOOKS_BY_AUTHOR_ID = "SELECT b.book_id AS b_id, b.title, b.price, b.amount, b.is_deleted, " +
"to_json(array_agg(DISTINCT aut.*)) as authors, to_json(array_agg(DISTINCT cat.*)) as categories " +
"FROM book b " +
"LEFT JOIN author_book AS ab ON b.book_id = ab.book_id " +
"LEFT JOIN author AS aut ON ab.author_id = aut.author_id " +
"LEFT JOIN category_book AS cb ON b.book_id = cb.book_id " +
"LEFT JOIN category AS cat ON cb.category_id = cat.category_id " +
"WHERE aut.author_id = :id " +
"GROUP BY b_id ORDER BY b_id ASC;";
}
顺便说一句,我已经更新了我的问题,以明确我是如何使用 resultQuery() 方法来实现我想要的。我在问如何在 jOOQ 中以尽可能多的类型安全方式实现这一点,因为我有更复杂的查询,我不知道是否可以通过不使用 PostgreSQL to_json()
函数来实现。例如,我想在 jOOQ 中创建类似 this 的内容,例如在 bytefish.de 网站提交的 link 的“04_create_functions.sql”部分。
get_image
--------------------------------------------------------------
{"imageid" : 1,
"hash" : "a3b0c44",
"description" : "Some Description",
"created_on" : "2015-03-09T22:00:45.111",
"comments" : [{"commentid":1, "imageid":1, "text":"Awesome!", "createdon":"2015-03-09T22:58:47.783"},
{"commentid":2, "imageid":1, "text":"This is just a second comment.", "createdon" : "2015-03-09T22:58:47.783"}],
"tags" : [{"tagid":1,"name":"Cool"},
{"tagid":2,"name":"Berlin"}]}
(1 row)
我正在尝试为 (book) ORDERS 的 REPORT 做同样的事情,其中涉及 8 tables 的查询(我没有 post 这里的查询试图解决 jOOQ 中更简单的问题,即创建 JsonArray)。
您的具体错误
- 您将
Field
表达式 (DSL.jsonArray()
) 包装在DSL.val()
中,这意味着绑定值。那是行不通的,是您异常的原因 - 但是,您还不能通过以这种方式将普通数组包装成
JSON
数组。 jOOQ 不知道你的意思是在幕后调用to_json
。从 jOOQ 3.13 开始,您将不得不求助于使用一些 plain SQL templating(请参见下面的示例),或者您获取一个数组而不将其转换为 JSON 在您的 SQL 逻辑中,并且仅在您的 Java 客户端逻辑中将其转换为 JSON。
普通 SQL 模板示例:
DSL.field("to_json({0})", JSON.class, DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID))
jOOQ 3.14 JSON 支持
请注意,jOOQ 3.14 将通过标准 SQL JSON API 和 SQL 服务器的 FOR JSON
子句:
JSON_ARRAY
,JSON_OBJECT
,JSON_VALUE
function supportJSON_ARRAYAGG
supportJSON_OBJECTAGG
supportJSON_TABLE
table valued function supportJSON_EXISTS
predicate support
并且:
正如@Lukas_Eder 指出要解决此问题,需要通过普通 SQL 模板创建 JSON 对象,如下例所示:
DSL.field("to_json({0})", JSON.class, DSL.arrayAggDistinct(AUTHOR.AUTHOR_ID))
我在文档中阅读了更多关于上述方法的内容,并了解了如何根据自己的需要修改方法(以便与 PostgreSQL 语法中有问题的方法相等):
DSL.field( "to_json(array_agg(DISTINCT author.*))", JSON.class, DSL.arrayAgg(AUTHOR.AUTHOR_ID) ).as("authors")