仅从 PostgreSQL 中 Java Date 类格式的字段按年份分组

Posted

技术标签:

【中文标题】仅从 PostgreSQL 中 Java Date 类格式的字段按年份分组【英文标题】:Group by year only from field which is in Java Date class format in PostgreSQL 【发布时间】:2015-10-21 08:29:11 【问题描述】:

我在 PostgreSQL 中工作,我有表名 my_table 架构

CREATE TABLE my_table
(
  my_table_id character varying(50) NOT NULL,
  bar_id character varying(50),
  beer_id character varying(50),
  status_id character varying(50),

  updated_at bigint,

  CONSTRAINT my_table_id PRIMARY KEY (craft_bar_beer_id ),
  CONSTRAINT my_table_bar_id_fk FOREIGN KEY (bar_id)
      REFERENCES table_bar (bar_id) MATCH Unknown
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT beer_status_id_fk FOREIGN KEY (status_id)
      REFERENCES status (status_id) MATCH Unknown
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT beer_id_fk FOREIGN KEY (beer_id)
      REFERENCES beer (beer_id) MATCH Unknown
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

现在输出是 beer_id 的计数,其状态为“1”和“2”并按日期分组(此处假设提供 2016 年或应显示过去 10 年的记录)

count(beer_id)   status     year
4                  1        2014
5                  1        2015
3                  2        2014
6                  2        2016

但这里updated_at 字段是bigint,它是从Java Date 对象派生的以毫秒为单位的时间:

Date dateValue = null;
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
dateValue = formatter.parse(dateStr);
return dateValue.getTime();

我试过的查询:

SELECT count(cbeer.beer_id) AS beers, cbeer.status_id AS Status
FROM my_table cbeer
INNER JOIN bar cb ON cb.bar_id = cbeer.bar_id
WHERE status_id IN ('1','2')
GROUP BY cbeer.status_id;

输出:

beers Status
5      1
1      2

当日期很长并且我希望它按过去 10 年分组时,如何查询以获取日期明智的记录。如果为 ex: 2015 提供年份,则按 2015 分组并获取该年的月份相关记录。

【问题讨论】:

一开始就将时间戳存储为 long 并不是一个好主意(您现在明白为什么了)。但是您可以使用 to_timestamp() 将 unix 纪元值转换为时间戳。详见手册postgresql.org/docs/current/static/functions-formatting.html 您说时间以毫秒为单位并存储在long 中。你能给我们看一个样本吗?你确定它是毫秒而不是秒吗? @Patrick 是的,我已将字符串中的日期转换为以毫秒为单位的时间,并将其存储在数据类型 bigint 中。你想让我给你看什么样品? 您能否举例说明如何将此字符串转换为bigint?原因是存储在bigint 中的“日期”(大概是时间)需要一些参考点。值 0 表示什么日期 + 时间? PostgreSQL 中的旧标准是以 bigint 格式存储 timestamp,Unix 默认为 0 点以秒为单位。因此我的问题。 日期 dateValue = null;SimpleDateFormat formatter = new SimpleDateFormat(dateFormat); formatter.setTimeZone(TimeZone.getTimeZone("GMT")); dateValue = formatter.parse(dateStr);返回 dateValue.getTime(); 【参考方案1】:

Java Date.getTime() 函数将对象作为 long 返回自 1970 年 1 月 1 日以来的毫秒数。幸运的是,这是 PostgreSQL 使用的同一时期,因此您可以简单地将值除以 1,000 并转换为 timestamp 以拥有对 PostgreSQL 日期和时间函数的完全访问权限:

to_timestamp(updated_at / 1000.)

现在您的查询。过去 10 年:

SELECT count(cbeer.beer_id) AS beers,
       cbeer.status_id AS Status,
       extract('year' from to_timestamp(updated_at / 1000.)) AS year
FROM my_table cbeer
INNER JOIN bar cb ON cb.bar_id = cbeer.bar_id
WHERE status_id IN ('1','2')
  AND extract('year' from to_timestamp(updated_at / 1000.)) > 2005
GROUP BY 2, 3
ORDER BY 2, 3, 1;

当月:

SELECT count(cbeer.beer_id) AS beers,
       cbeer.status_id AS Status,
       extract('month' from to_timestamp(updated_at / 1000.)) AS month
FROM my_table cbeer
INNER JOIN bar cb ON cb.bar_id = cbeer.bar_id
WHERE status_id IN ('1','2')
  AND extract('year' from to_timestamp(updated_at / 1000.)) = 2015
GROUP BY 2, 3
ORDER BY 2, 3, 1;

【讨论】:

您还需要找到架构设计者并“教育”他们。牢牢。在 bigint 中存储日期,呃。 @CraigRinger 如此热情地想说的是:不要将 Java 内部格式存储在数据库中。而是使用 PreparedStatement.setDate() 之类的东西,这样您就可以获得 DBMS 可以理解和操作的数据。

以上是关于仅从 PostgreSQL 中 Java Date 类格式的字段按年份分组的主要内容,如果未能解决你的问题,请参考以下文章

如何仅从 PostgreSQL 的内部联接中不存在 id 的表中选择行?

气流导出模式仅从 PostgreSQL 到 bigquery

postgresql的timestamp对应java啥类型

Java,PostgreSQL时间范围查询

仅从控制器通过DateTime对象传递日期。尝试多种方式绑定时间

如何仅从日期时间列中获取日期? [复制]