微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我有一个包含 timestamp 类型列的 Postgresql 表。不久前我已经包含了这个专栏,以防我将来想用它来做某事。我现在希望将其转换为 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

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

解决方法

首先,目标是未定义的,没有明确 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 之间进行转换(只要值兼容)。

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

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

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

最后,不要这样做。数据类型timestamp(或timestamptz)通常在多种方面优于将时间信息存储为通用bigint。在 Laurenz 的回答中查看详细信息!

见:

,

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

  • 人类更容易理解这些值

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

    timestamp - timestamp → interval

    timestamp + interval → timestamp

    interval / double precision → interval

    这使您的查询更具可读性

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

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

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

实际转换在 Erwin 的回答中给出,所以我不会在这里重复。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。