【问题标题】:JOOQ: Result.getValues() returns list with null entryJOOQ:Result.getValues() 返回带有空条目的列表
【发布时间】:2014-09-16 18:35:42
【问题描述】:

我使用 JOOQ 查询多对多关系,并且需要将一个条目的多个结果映射到单个对象。为此,我使用唯一标识符将结果分组,并从每个分组结果中提取所需的数据。对于多对多数据,我获取所有可用值,对于普通数据,我只使用第一个条目的数据:

Map<String, Result<Record2<String, String>> groupedResults = create.select(LOC.NAME, GROUP.GROUP_)
    .from(LOC)
    .leftOuterJoin(LOC2GROUP)
    .on(Tables.LOC2GROUP.LOC_ID.eq(LOC.LOC_ID))
    .leftOuterJoin(GROUP)
    .on(LOC2GROUP.GROUP_ID.eq(GROUP.GROUP_ID))
    .fetch().intoGroups(LOC.NAME);

Collection<Loc> ret = new ArrayList<Loc>();
for (Result<Record2<String, String>> result : groupedResults.values()) {
    Loc loc = new Loc(result.getValue(0, LOCATION.NAME), result.getValues(Tables.GROUP.GROUP_));
    ret.add(loc);
}

现在,虽然每个条目可以有多个组,但它不需要有任何组,以下将是一个有效的条目,只是没有设置任何组:

|name  |group |   
|simple|{null}|

奇怪的是,我注意到Result.getValues() 在这种情况下会返回一个包含null 的列表,而不是一个空列表。

这是有意的吗?如果是这样,是否有比在获取后删除空条目更好的解决方法?

【问题讨论】:

  • 不应该有任何“意外”的空值,但很有可能将您的原始结果分组到 groupedResults 将在每个组中产生一个 null 值。您最初的查询是什么?原始查询在分组之前返回了哪些数据?
  • @LukasEder 查询是几个连接的相当复杂的混乱,我在上面添加了一个简化示例。在分组之前,查询将返回如上例 (2) 所示的数据。如果 JOOQ 在这里按预期工作,我假设我唯一能做的就是在之后删除不需要的空值(再次,对于我的内部逻辑,空值意味着“没有组”,它在内部由一个空集合表示)?

标签: sql many-to-many jooq


【解决方案1】:

您在查询中使用了OUTER JOIN。这意味着您的结果集可能确实包含来自LOC 表的值,但没有来自GROUP 表的对应值。以下是您查询的一些有效示例输出:

+------+--------+
| name | group  |
+------+--------+
| a    | x      |
| a    | y      |
| b    | x      |
| c    | {null} | <-- there's a value in LOC, but no corresponding value in GROUP
+------+--------+

现在,当您在该结果上调用 jOOQ 的 intoGroups() 时,jOOQ 只会看到 3 个组:abc,这会为您提供以下 Map(使用 JSON 作为伪符号):

{
    "a" : [ { "name" : "a", "group" : "x"  },
            { "name" : "a", "group" : "y"  } ],
    "b" : [ { "name" : "b", "group" : "x"  } ],
    "c" : [ { "name" : "c", "group" : null } ]
}

仅仅因为其中一列中恰好有一个null 值并不意味着这个null 值在分组时应该具有任何语义。这一列 (group) 是您唯一感兴趣的列这一事实并没有改变分组结果是记录而不是单个值的事实。

我希望这是有道理的?

jOOQ 目前不支持返回您真正需要的数据结构的方法:

{
    "a" : [ "x", "y" ],
    "b" : [ "x" ],
    "c" : [ ]
}

不过自己写这样一个实用方法应该还是挺容易的……

PostgreSQL 或 HSQLDB 解决方案:

或者,如果您使用的是 PostgreSQL 或 HSQLDB,则可以改用 array_agg()

Result<Record2<String, String[]>> result =
create.select(LOC.NAME, arrayAgg(GROUP.GROUP_))
      .from(LOC)
      .leftOuterJoin(LOC2GROUP)
      .on(Tables.LOC2GROUP.LOC_ID.eq(LOC.LOC_ID))
      .leftOuterJoin(GROUP)
      .on(LOC2GROUP.GROUP_ID.eq(GROUP.GROUP_ID))
      .groupBy(LOC.NAME)
      .fetch();

DSL.arrayAgg() 将成为 jOOQ 3.5 的一部分,但您可以自己创建该 jOOQ 函数:

@Support({SQLDialect.POSTGRES})
protected static <T> Field<T[]> arrayAgg(Field<T> field) {
    return DSL.field("array_agg({0})", field.getDataType().getArrayDataType(), field);
}

【讨论】:

    猜你喜欢
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多