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

Posted

技术标签:

【中文标题】如何在 Jooq 中按月和年将毫秒翻译成日期和分组?【英文标题】:How to translate millis to date and group by month and year in Jooq? 【发布时间】:2020-07-05 05:56:55 【问题描述】:

我有以下按预期工作的 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 的毫秒数创建一个 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?

【问题讨论】:

【参考方案1】:

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

一些方言可能“为了方便”实现了异常,但这通常很令人困惑。我建议不要这样做。

但是要解决你的问题:

产生你想产生的 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 子句,您无需手动重复它们。

【讨论】:

非常感谢您的解释,@Lukas Eder 目前我被如何从 TRANSACTION.CREATION_DATE 创建日期的问题所阻止,因为数据库中的数据类型很长,它是unix 时间戳 @AnnaIraHurnaus:我很乐意回答一个新的、单独的问题 这里是单独的问题:***.com/questions/60848890/…

以上是关于如何在 Jooq 中按月和年将毫秒翻译成日期和分组?的主要内容,如果未能解决你的问题,请参考以下文章

在 postgresql 中按月和年对查询结果进行分组

Django按月和年过滤

Drupal 视图 UI,过滤器暴露,集合字段内容中的日期仅按月和年(无天)

什么策略建议按月和年分配数据帧以获得R中的单个数据帧列表

仅按月和年选择数据

如何在 Pandas 中按年和月加入 2 个数据框?