如何在 Jooq 中按月和年翻译毫秒到日期和分组?

How to translate millis to date and group by month and year in Jooq?

我有以下 SQL 可以按预期工作:

select  YEAR(CONVERT_TZ(FROM_UNIXTIME(creation_date / 1000), @@session.time_zone, "Europe/Berlin")) as year,
    MONTH(CONVERT_TZ(FROM_UNIXTIME(creation_date / 1000), @@session.time_zone, "Europe/Berlin")) as month,
    sum(value)
from transaction
GROUP BY year, month; 

我正在尝试在 Jooq 中重新创建这些 SQL,但我不知道如何从我在数据库中 creation_date 拥有的毫秒创建日期对象。

dsl.select(DSL.month(DSL.date(TRANSACTION.CREATION_DATE)), // This does not work
           DSL.year(DSL.date(TRANSACTION.CREATION_DATE)), // This does not work
           DSL.sum(TRANSACTION.VALUE))
       .from(TRANSACTION)
       .groupBy(???); // How to group by month and year?

写 SQL GROUP BY 时的一个常见混淆是 the logical order of SQL operations。虽然在句法上,SELECT 似乎出现在 GROUP BY 之前,但逻辑上顺序是相反的。这意味着您不能真正从 GROUP BY 子句中引用 SELECT 子句中的列。

有些方言可能已经实现了例外 "for convenience",但这通常非常令人困惑。我建议不要那样做。

但是要解决你的问题:

生产你想生产的SQL

虽然在您的原始 SQL 查询中,您为两个表达式(AS yearAS month)使用了别名,但在 jOOQ 查询中您没有。我建议您也使用别名,并将列表达式分配给局部变量,以便在 groupBy() 子句中重用:

Field<?> month = DSL.month(DSL.date(TRANSACTION.CREATION_DATE)).as("month");
Field<?> year  = DSL.year(DSL.date(TRANSACTION.CREATION_DATE)).as("year");

dsl.select(month, year, DSL.sum(TRANSACTION.VALUE))
   .from(TRANSACTION)
   .groupBy(month, year)
   .fetch();

别名列在 SELECT 子句中生成完整声明,但在所有其他子句中仅生成别名,因此这正是您想要的:

SELECT
  month(date(transaction.creation_date)) as month,
  year(date(transaction.creation_date)) as year
  sum(transaction.value)
FROM transaction
GROUP BY
  month,
  year;

一个更好的SQL语句根据操作的逻辑顺序

如果您希望您的 SQL 保持可移植性并根据我提到的 SQL 操作的逻辑顺序正确,我建议您改为这样写:

Field<?> month = DSL.month(DSL.date(TRANSACTION.CREATION_DATE));
Field<?> year  = DSL.year(DSL.date(TRANSACTION.CREATION_DATE));

dsl.select(month.as("month"), year.as("year"), DSL.sum(TRANSACTION.VALUE))
   .from(TRANSACTION)
   .groupBy(month, year)
   .fetch();

请注意,我已将别名移至 SELECT 子句,而在 GROUP BY 子句中,我现在引用的是完整的列表达式。这将产生以下查询:

SELECT
  month(date(transaction.creation_date)) as month,
  year(date(transaction.creation_date)) as year
  sum(transaction.value)
FROM transaction
GROUP BY
  month(date(transaction.creation_date)),
  year(date(transaction.creation_date));

完整的表达式现在扩展到 GROUP BY 子句中,您无需手动重复它们。