获取 "value "3000002000" 超出整数类型的范围"

Getting "value "3000002000" is out of range for type integer"

我正在使用 Rails 4.2.3 和 PostGre 数据库。我希望我的数据库中的一列存储毫秒数——注意,不是时间戳,而是以毫秒为单位的持续时间。所以我像这样创建了我的专栏

time_in_ms | bigint

但是,当我去 Rails 中存储一个值时,出现以下错误

ActiveRecord::StatementInvalid (PG::NumericValueOutOfRange: ERROR:  value "3000002000" is out of range for type integer
: INSERT INTO "my_object_times" ("time_in_ms", "my_object_id", "created_at", "updated_at") VALUES (, , , ) RETURNING "id"):
  app/controllers/my_objects_controller.rb:31:in `update'

数字“3000002000”似乎小于该列的最大值(我正在阅读的是“9223372036854775807”),所以我想知道还有什么问题以及如何解决它。

编辑: 为了提供更多信息,在我的 db/schema.rb 文件中,相关列的描述如下...

create_table "my_object_times", force: :cascade do |t|
  ...
  t.integer  "time_in_ms",     limit: 8

编辑 2: 这是 PSQL

中创建 table 的输出
CREATE TABLE my_object_times (
    id integer NOT NULL,
    first_name character varying,
    last_name character varying,
    time_in_ms bigint,
    created_at timestamp without time zone NOT NULL,
    updated_at timestamp without time zone NOT NULL,
    name character varying,
    age integer,
    city character varying,
    state_id integer,
    country_id integer,
    overall_rank integer,
    age_group_rank integer,
    gender_rank integer
);

bigint 是 64 位,而 Rails 是 32 位。

3000002000 大于 2^32。这就是为什么将其转换为 32 位整数失败并显示 NumericValueOutOfRange

编辑: 我刚刚重新阅读了这篇文章,我原来的回答实际上对你的情况没有意义。我确实相信您需要在该专栏之外寻找答案,并手动确认您认为自己知道的关于它状态的每一点。任何细节的添加都将帮助我们找到正确的答案。 设置断点以单步执行请求并查看是否可以发现 integer

create_table "my_object_times", force: :cascade do |t| ... t.integer "time_in_ms", limit: 8

t.integer - 在我看来这就是你的罪魁祸首。 ... 好吧,我试过了,我最后的想法是它必须与某种 Rails 请求中间件有关,但我不知道具体细节是什么。请求路径中的某些东西认为该列是一个整数。直到现在我才明白 Rails 迁移数据类型是如何工作的,所以我学到了一些东西。 (而且我整天都在钓鱼,所以我会把这一天算作胜利。)祝你好运!

我猜,table my_object_times 可能不是从 schema.rb 文件创建的,或者它可能被其他迁移文件覆盖。因为在迁移文件中限制为 8 的整数列本身就是一个 bigint。所以你应该交叉检查来自 PG-admin 的 table 定义。如果该列不是 bigInt 则 运行 以下迁移

class ChangeTimeInMsToBigint < ActiveRecord::Migration
  def change
  execute <<-SQL
    ALTER TABLE my_object_times
    ALTER COLUMN time_in_ms TYPE bigint USING time_in_ms::bigint
  SQL
end
end

我之前遇到过这种情况,当我最初尝试在数据库中创建一个 bigint 字段时,出于某种原因模型认为它是一个整数,即使模式和迁移文件将它指定为大整数。

例如:我有这个迁移文件

class CreateSecureUserTokens < ActiveRecord::Migration
  def change
    create_table :secure_user_tokens do |t|
      t.integer :sso_id, null: false, length: 8
      t.string :token, null: false

      t.timestamps null: false
    end
  end
end

注意,它有包含长度:8 的要求,使整数成为 bigint。但是,在我 运行 迁移之后,我遇到了与您相同的问题。最终我只是创建了另一个迁移来尝试解决这个问题,它成功了。这是我用来解决问题的迁移:

class ModifySecureTokensForLargerSsoIdSizes < ActiveRecord::Migration
  def change
    change_column :secure_user_tokens, :sso_id, :integer, limit: 8
  end
end

因此,如果我们更改它以满足您的需求,它将是:

class ObjectTimesBigInt < ActiveRecord::Migration
  def change
    change_column :my_object_times, :time_in_ms, :integer, limit: 8
  end
end

希望对您有所帮助! -查理