【问题标题】:Does PostgreSQL support precision and scale for Rails?PostgreSQL 是否支持 Rails 的精度和规模?
【发布时间】:2023-04-06 15:17:01
【问题描述】:

我有一个 Rails 应用程序,它定义了一个迁移,其中包含精度为 8 和小数位数为 2 的小数。我设置的数据库是 PostgreSQL 9.1 数据库。

class CreateMyModels < ActiveRecord::Migration
    def change
        create_table :my_models do |t|
            t.decimal :multiplier, precison: 8, scale: 2
            t.timestamps
        end
    end
end

当我运行rake db:migrate 时,迁移成功发生,但我在尝试运行MyModel.find_or_create_by_multiplier 时发现了一个错误。如果我运行以下命令两次,对象将被创建两次:

MyModel.find_or_create_by_multiplier(multiplier: 0.07)

我假设这应该在第一次调用期间创建对象,然后在第二次调用期间find对象。不幸的是,当乘数设置为 0.07 时,这似乎不会发生。

对于我在上述命令中抛出的每个其他数字,此 DOES 都按预期工作。以下命令按预期工作(在第一次调用期间创建对象,然后在第二次调用期间找到对象)。

MyModel.find_or_create_by_multiplier(multiplier: 1.0)

MyModel.find_or_create_by_multiplier(multiplier: 0.05)

MyModel.find_or_create_by_multiplier(multiplier: 0.071)

当我查看MyModel表的PostgreSQL数据库描述时,我注意到该表对数值列没有限制。

   Column    |            Type             |                         Modifiers
-------------+-----------------------------+-------------------------------------------------------
 id          | integer                     | not null default nextval('my_models_id_seq'::regclass)
 multiplier  | numeric                     | 
 created_at  | timestamp without time zone | not null
 updated_at  | timestamp without time zone | not null

我的 db/schema.rb 文件也没有说明精度和比例:

ActiveRecord::Schema.define(:version => 20121206202800) do

...
    create_table "my_models", :force => true do |t|
        t.decimal  "multiplier"
        t.datetime "created_at",                   :null => false
        t.datetime "updated_at",                   :null => false
    end
...

所以我的第一个问题是,为什么我在迁移时没有看到将精度和规模推低到 PostgreSQL? Documentation states that it should be supported.

我的第二个问题是,为什么使用MyModel.find_or_create_by_multiplier(multiplier: 0.07) 命令不能正确比较 0.07? (如果我需要为此提出另一个问题,我会的)。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 postgresql


    【解决方案1】:

    这太尴尬了……

    我拼错了。

    将迁移更改为:

    t.decimal :multiplier, precision: 8, scale: 2
    

    修复一切。

    【讨论】:

    • 我什至没有注意到这一点。我想知道您为什么没有收到错误消息?
    • 我只是在说同样的话。我回顾了我的 shell 历史,除了索引通知之外,输出什么也没说。它基本上默默地​​失败了......仍然添加列,但忽略列的拼写错误的属性。
    【解决方案2】:

    PostgreSQL 9.1 将允许您以任何这些方式声明列。

    column_name decimal
    column_name numeric
    column_name decimal(8, 2)
    column_name numeric(8, 2)
    

    如果您使用 pgAdminIII 来查看该列,它将准确地显示它是如何创建的。如果您(或 Rails)将该列创建为numeric,它将显示“数字”。如果您(或 Rails)将该列创建为 decimal(8, 2),它将显示“decimal(8, 2)”。

    所以在我看来 Rails 并没有将精度和规模传递给 PostgreSQL。相反,它只是告诉 PostgreSQL 创建类型为“numeric”的列。 Rails docs 建议它应该这样做。

    该链接中的示例语法与您的不同。

    td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
    

    【讨论】:

      【解决方案3】:

      一开始我使用的是:numeric。尽管 ActiveRecord 为我将其更改为 :decimal,但 :precision:scale 都被忽略了。

      # 202001010000000_add_my_col_to_my_table.rb
      add_column :my_table, :my_col :numeric, percision: 3, scale: 2, comment: 'Foobar'
      
      # schema.rb
      t.decimal "my_col", comment: 'Foobar'
      

      只需在迁移文件中更改为 :decimal 即可为我修复它:

      # 202001010000000_add_my_col_to_my_table.rb
      add_column :my_table, :my_col :decimal, percision: 3, scale: 2, comment: 'Foobar'
      
      # schema.rb
      t.decimal "my_col", precision: 3, scale: 2, comment: 'Foobar'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-27
        • 2012-04-01
        • 2010-11-09
        • 2012-06-15
        • 1970-01-01
        • 1970-01-01
        • 2015-07-21
        • 1970-01-01
        相关资源
        最近更新 更多