如何将时间戳字段转换为 int8?或者只是删除该列并创建一个新列?

Posted

技术标签:

【中文标题】如何将时间戳字段转换为 int8?或者只是删除该列并创建一个新列?【英文标题】:How to convert a timestamp field to int8? Or just drop the column and make a new one? 【发布时间】:2021-08-14 05:56:12 【问题描述】:

我有一个 PostgreSQL 表,其中有一列类型为 timestamp。前段时间我已经收录了这个专栏,以防我将来想用它做一些事情。我现在希望将其转换为 int8 并将其用作纪元时间列。目前,表的所有行都将此列设置为null。当我尝试使用以下方法更改行时:

ALTER TABLE public.new_ambient_data
ALTER COLUMN sensor_date TYPE int8 USING sensor_date::int8;

我得到错误:

ERROR: cannot cast type timestamp without time zone to bigint

是直接删除列并创建一个新的我想要的数据类型更好,还是这里有一个更好的 SQL 脚本来将空的 timestamp 列转换为 int8

注意:有问题的表中有超过一百万行。

【问题讨论】:

blog.sql-workbench.eu/post/epoch-mania 【参考方案1】:

首先,在没有明确int8 将代表什么的情况下,目标是不确定的。自纪元以来的秒数?毫秒?微秒? (在您的特定情况下,所有 NULL 值都无关紧要,但下一位读者可能会被误导。)

接下来,在 Postgres 中没有为 timestamp 定义演员表 --> bigint (基本上出于相同的原因)。 USING 子句需要一个有效的表达式。

假设您需要微秒,因为这会保留 Postgres 时间戳的原始微秒分辨率,这样就可以完成这项工作:

ALTER TABLE public.new_ambient_data
   ALTER COLUMN sensor_date TYPE int8 USING (extract(epoch FROM sensor_date)*1000000)::int8;

值得注意的是,时间戳的 Postgres 纪元从 2000-01-01 00:00:00 UTC 开始,与 UNIX 纪元从 1970-01-01 00:00:00 UTC 开始。但是extract() 返回 UNIX 纪元(可以用to_timestamp() 转换回timestamptz)。所以只转换内部值是不行的。

对于您的特定情况(所有值为 NULL),使用text 作为垫脚石会更简单。每种类型都可以从text 转换为text(只要值兼容)。

ALTER TABLE public.new_ambient_data
   ALTER COLUMN sensor_date TYPE int8 USING sensor_date::text::int8;

是的,就地转换列可能比删除并重新创建它更便宜。虽然该列全部为 NULL,但无论哪种方式,操作都非常便宜,因为没有实际的元组数据,只有 NULL 位图中的一个位。两种方式都不会触发表重写。

新添加的列始终位于列列表的末尾,而转换后的列则保持原位。取决于你想要什么。

最后,不要这样做。数据类型timestamp(或timestamptz)通常优于以多种方式将时间信息存储为通用bigint。请参阅 Laurenz 的答案中的详细信息!

见:

Ignoring time zones altogether in Rails and PostgreSQL How to get the date and time from timestamp in PostgreSQL select query? How to round off milliseconds value from timestamp(0) in PostgreSQL?

【讨论】:

【参考方案2】:

首先,我想劝阻你不要这样做。使用timestamp 列比使用数字列要好得多:

这些值更容易被人类理解

你可以使用日期算术,所以你不会丢失任何东西:

timestamp - timestamp → interval

timestamp + interval → timestamp

interval / double precision → interval

这使您的查询更具可读性

如果您使用timestamp with time zone,您可以让 PostgreSQL 为您处理时区转换

有用的函数,如 date_partdate_trunc(以及从 v14 开始的 date_bin!)截断值并提取单个组件

在内部,时间戳无论如何都会存储为数字,因此您不会失去性能。

实际转换在欧文的回答中给出,这里不再赘述。

【讨论】:

以上是关于如何将时间戳字段转换为 int8?或者只是删除该列并创建一个新列?的主要内容,如果未能解决你的问题,请参考以下文章

将 C 字符数组转换为字符串

使用 Kafka Connect 时如何转换所有时间戳字段?

如何将具有时间戳字段的firestore doc数据转换为通过Freezed dart包生成的数据类?

如何将 Hive 表中的所有时间戳转换为 EAT

将MYSQL数据库里的时间戳转换成时间

如何将时间戳(yyyy-mm-dd-h-m-s 转换为日期(yyyy-mm-dd)