LATERAL无效的JOOQ语句(Postgresql)

时间:2014-03-19 12:23:59

标签: java sql postgresql jooq

问题

我正在尝试将以下SQL语句转换为JOOQ:

SELECT g.id, g.machine_id,
       xmin.min_trans_id,
       xmax.max_id
FROM   machine_location_move_events g
  , LATERAL 
       ( SELECT c.ts AS min_ts, c.id AS min_id, c.transaction_id AS min_trans_id
         FROM machine_economy_counters c
         WHERE c.move_event_id = g.id
           AND c.ts BETWEEN timestamp '2012-03-02 00:00:00'
                        AND timestamp '2014-03-05 12:00:00'
         ORDER BY c.ts ASC
         LIMIT 1
       ) xmin
  , LATERAL 
       ( SELECT c.ts AS max_ts, c.id AS max_id, c.transaction_id AS max_trans_id
         FROM machine_economy_counters c
         WHERE c.move_event_id = g.id
           AND c.ts BETWEEN timestamp '2012-03-02 00:00:00'
                        AND timestamp '2014-03-05 12:00:00'
         ORDER BY c.ts DESC 
         LIMIT 1
       ) xmax
WHERE xmin.min_ts IS NOT NULL ;

我的JOOQ java代码如下所示:

@Test
public void getTotalBetween() {
    DateTime from = new DateTime(2012, 3, 2, 0, 0, DateTimeZone.forID("Europe/Copenhagen"));
    DateTime to = new DateTime(2014, 3, 5, 12, 0, DateTimeZone.forID("Europe/Copenhagen"));

    DSLContext dslContext = jooqProvider.getDSLContext();

    SelectOffsetStep<Record3<Timestamp, Long, Long>> innerMinSelect;
    {
        MachineLocationMoveEvents gTable = MACHINE_LOCATION_MOVE_EVENTS.as("g");
        MachineEconomyCounters cTable = MACHINE_ECONOMY_COUNTERS.as("c");

        Field<Timestamp> min_ts = min(cTable.TS).as("min_ts");
        Field<Long> min_id = cTable.ID.as("min_id");
        Field<Long> min_transaction_id = cTable.TRANSACTION_ID.as("min_trans_id");

        innerMinSelect = dslContext.select(min_ts, min_id, min_transaction_id)
                  .from(cTable)
                  .where(cTable.MOVE_EVENT_ID.eq(gTable.ID)
                         .and(cTable.TS.between(new Timestamp(from.getMillis()), new Timestamp(to.getMillis()))))
                  .orderBy(cTable.TS.asc())
                  .limit(1)
                  ;
    }

    SelectOffsetStep<Record3<Timestamp, Long, Long>> innerMaxSelect;
    {
        MachineLocationMoveEvents gTable = MACHINE_LOCATION_MOVE_EVENTS.as("g");
        MachineEconomyCounters cTable = MACHINE_ECONOMY_COUNTERS.as("c");

        Field<Timestamp> max_ts = min(cTable.TS).as("max_ts");
        Field<Long> max_id = cTable.ID.as("max_id");
        Field<Long> max_transaction_id = cTable.TRANSACTION_ID.as("max_trans_id");

        innerMaxSelect = dslContext.select(max_ts, max_id, max_transaction_id)
                  .from(cTable)
                  .where(cTable.MOVE_EVENT_ID.eq(gTable.ID)
                         .and(cTable.TS.between(new Timestamp(from.getMillis()), new Timestamp(to.getMillis()))))
                  .orderBy(cTable.TS.desc())
                  .limit(1)
                  ;
    }

    MachineLocationMoveEvents gTable = MACHINE_LOCATION_MOVE_EVENTS.as("g");
    MachineEconomyCounters cTable = MACHINE_ECONOMY_COUNTERS.as("c");
    Field<Long> min_transaction_id = cTable.TRANSACTION_ID.as("min_trans_id");
    Field<Long> max_id = cTable.ID.as("max_id");
    Field<Timestamp> min_ts = min(cTable.TS).as("min_ts");

    Table<Record3<Timestamp, Long, Long>> minLateral = lateral(innerMinSelect).as("xmin");
    Table<Record3<Timestamp, Long, Long>> maxLateral = lateral(innerMaxSelect).as("xmax");

    SelectConditionStep<Record4<Integer, Integer, Long, Long>> minMaxSelect = dslContext.select(gTable.ID, gTable.MACHINE_ID, minLateral.field(min_transaction_id), maxLateral.field(max_id))
              .from(gTable, minLateral, maxLateral)
              .where(minLateral.field(min_ts).isNotNull());

    System.out.println(minMaxSelect.fetch());
}

但是,当我运行测试时,我会收到此错误消息:ERROR: column "c.id" must appear in the GROUP BY clause or be used in an aggregate function

完整错误:

org.jooq.exception.DataAccessException: SQL [select "g"."id", "g"."machine_id", "xmin"."min_trans_id", "xmax"."max_id" from "public"."machine_location_move_events" as "g", lateral (select min("c"."ts") as "min_ts", "c"."id" as "min_id", "c"."transaction_id" as "min_trans_id" from "public"."machine_economy_counters" as "c" where ("c"."move_event_id" = "g"."id" and "c"."ts" between cast(? as timestamp) and cast(? as timestamp)) order by "c"."ts" asc limit ? offset ?) as "xmin", lateral (select min("c"."ts") as "max_ts", "c"."id" as "max_id", "c"."transaction_id" as "max_trans_id" from "public"."machine_economy_counters" as "c" where ("c"."move_event_id" = "g"."id" and "c"."ts" between cast(? as timestamp) and cast(? as timestamp)) order by "c"."ts" desc limit ? offset ?) as "xmax" where "xmin"."min_ts" is not null]; ERROR: column "c.id" must appear in the GROUP BY clause or be used in an aggregate function
  Position: 171
    at org.jooq.impl.Utils.translate(Utils.java:1287)
    at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:495)
    at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:326)

Caused by: org.postgresql.util.PSQLException: ERROR: column "c.id" must appear in the GROUP BY clause or be used in an aggregate function
  Position: 171
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2161)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1890)

错误消息中的SQL在格式化时看起来像这样:

select "g"."id", "g"."machine_id",
       "xmin"."min_trans_id", 
       "xmax"."max_id" 
from "public"."machine_location_move_events" as "g"
  , lateral 
       ( select min("c"."ts") as "min_ts", "c"."id" as "min_id", "c"."transaction_id" as "min_trans_id" 
         from "public"."machine_economy_counters" as "c" 
         where ("c"."move_event_id" = "g"."id" 
           and "c"."ts" between cast(? as timestamp) 
                            and cast(? as timestamp))
         order by "c"."ts" asc 
         limit ? offset ?
       ) as "xmin"
  , lateral 
       ( select min("c"."ts") as "max_ts", "c"."id" as "max_id", "c"."transaction_id" as "max_trans_id" 
         from "public"."machine_economy_counters" as "c" 
         where ("c"."move_event_id" = "g"."id" 
           and "c"."ts" between cast(? as timestamp) 
                            and cast(? as timestamp)) 
         order by "c"."ts" desc 
         limit ? offset ?
       ) as "xmax" 
where "xmin"."min_ts" is not null

据我所知,这个SQL看起来非常像上面发布的那个,它直接在PostgreSQL 9.3.3服务器上运行时有效。

问题

我的SQL语句不包含GROUP BY,那么为什么PostgreSQL驱动程序声明我需要它?

我在JOOQ声明中做错了吗?

额外信息

  • PostgreSQL驱动版本:9.3-1101-jdbc41
  • JOOQ版本:3.3.0
  • Java版本:1.7

0 个答案:

没有答案