【问题标题】:Can't change the type of a column from date to integer无法将列的类型从日期更改为整数
【发布时间】:2020-07-09 21:54:13
【问题描述】:

我目前正在尝试使用找到here 的解决方案,但我似乎无法将用户列的类型从date 更改为integer

当我尝试时:

ALTER TABLE users ALTER COLUMN password_reset_expires TYPE integer;

我收到此错误:

ERROR:  column "password_reset_expires" cannot be cast automatically to type integer
HINT:  You might need to specify "USING password_reset_expires::integer".

当我尝试时:

ALTER TABLE users ALTER COLUMN password_reset_expires TYPE integer
USING (password_reset_expires::integer);

错误告诉我:

ERROR:  cannot cast type date to integer
LINE 1: ...expires TYPE integer USING (password_reset_expires::integer)...

我的表定义:

                                            Table "public.users"
         Column         |          Type          | Collation | Nullable |              Default
------------------------+------------------------+-----------+----------+-----------------------------------
 id                     | bigint                 |           | not null | nextval('users_id_seq'::regclass)
 name                   | character varying(20)  |           | not null |
 email                  | character varying(100) |           | not null |
 password               | character varying(500) |           | not null |
 password_changed_at    | date                   |           |          |
 password_reset_token   | character varying(300) |           |          |
 password_reset_expires | date                   |           |          |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "tokens" CONSTRAINT "tokens_token_pk_fkey" FOREIGN KEY (fk_users_id) REFERENCES users(id)

这是我的用户对象之一:

{
  id: '59',
  name: 'visitor',
  email: 'visitor',
  password: '$2b$10$0UGgdRUlXFYeQfk5Nv/vXe9khdzyyOqsTiFGyNXLfEDuOFAt0xc1G',
  password_changed_at: null,
  password_reset_token: null,
  password_reset_expires: null
}

【问题讨论】:

  • 请提供样本数据和期望的结果。对于给定日期,您想要什么值并不明显。
  • @GordonLinoff 刚刚在最后添加了一个用户示例。我想在password_reset_expirespassword_changed_at 中存储的是这样的数字 1594329364292
  • 您为什么要开始这样做?日期值应存储在date 列中,日期/时间值应存储在timestamptimestamptz 列中。不要使用愚蠢的时代来做到这一点。 blog.sql-workbench.eu/post/epoch-mania

标签: sql postgresql date types ddl


【解决方案1】:

基本上,使用 SQL 标准函数 EXTRACT()。你的comment

我想在password_reset_expirespassword_changed_at 中存储的是一个像这样的数字 1594329364292

... 表示您希望将 自 UNIX 纪元 1970-01-01 00:00:00 以来的毫秒数存储为整数值。但这超出了type integer(签名int4)的范围,它允许的数字最大为2^31 - 1 = 2147483647。在撰写本文时,自纪元以来已经过去了 1594335691272 毫秒。

integer 列中存储

ALTER TABLE users ALTER COLUMN password_reset_expires TYPE integer
USING (EXTRACT(EPOCH FROM password_reset_expires)::int);

或将 毫秒 存储在 bigint 列中
(签名int8,最多允许2^63 - 1 = 9223372036854775807):

ALTER TABLE users ALTER COLUMN password_reset_expires TYPE bigint -- !
USING (EXTRACT(EPOCH FROM password_reset_expires)::bigint * 1000);

EXTRACT(EPOCH FROM ...)返回,根据the manual

对于timestamp with time zone 值,自 1970-01-01 00:00:00 UTC(可以是负数);对于datetimestamp 值,自本地时间 1970-01-01 00:00:00 以来的秒数; 对于interval 值,间隔内的总秒数

由于在这种情况下源是date,所以不能有小数秒,我们可以乘以 1000 得到毫秒数。

再一次,如果不能有毫秒,为什么要存储开始的毫秒数?

更重要的是,为什么不保留date?如果该值实际上表示日期,则数据类型date 几乎可以肯定是最佳选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    相关资源
    最近更新 更多