Рельсы — плавающая точность

#ruby-on-rails #database #floating-point #migration

#ruby-on-rails #База данных #с плавающей запятой #миграция

Вопрос:

У меня есть атрибут float, и у меня проблемы с точностью. Если сохранить значение типа «745.34», оно правильно сохраняется в базе данных. Однако, если я попытаюсь сохранить, например, 4564523.845, это сохранит 4564520.0. Думаю, это не такое большое число, чтобы float его не поддерживал. Какой-нибудь пример моей консоли:

 c.valor_total = 4564523.845
 => 4564523.845 
2.3.1 :034 > c.save
   (0.3ms)  BEGIN
  UnidadeConsumidora Load (0.3ms)  SELECT  `unidade_consumidoras`.* FROM `unidade_consumidoras` WHERE `unidade_consumidoras`.`id` = 28 LIMIT 1
  SQL (21.2ms)  UPDATE `contas` SET `valor_total` = 4564523.845, `updated_at` = '2016-10-20 17:28:20' WHERE `contas`.`id` = 28
   (70.4ms)  COMMIT
 => true 
2.3.1 :035 > c = Conta.find 28
  Conta Load (0.9ms)  SELECT  `contas`.* FROM `contas` WHERE `contas`.`id` = 28 LIMIT 1
 => #<Conta id: 28, unidade_consumidora_id: 28, razao_social: "DROGARIA ARAUJO S A", ano: 2016, mes: 8, numero_cliente: "7000042467", cnpj: "17.256.512/0001-16", consumo_kwh: "10942", vencimento: "2016-10-18", valor_total: 4564520.0, created_at: "2016-10-19 18:43:35", updated_at: "2016-10-20 17:28:20", pdf_conta: "ADOLPHO_COTTA.pdf", unidade_de_leitura: "07020129", cod_instalacao: "3000728720", logradouro: "PCA ALEXANDRE LANZA 141 CO .", bairro: "CENTRO", cep: "35700-040", municipio: "SETE LAGOAS", uf: "MG"> 
2.3.1 :036 > c.valor_total
 => 4564520.0
  

Посмотрите, что в журнале обновления sql значение правильное… итак, что это может быть и как это исправить?

Редактировать:

schema.rb для contas:

   create_table "contas", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
    t.integer  "unidade_consumidora_id"
    t.string   "razao_social"
    t.integer  "ano"
    t.integer  "mes"
    t.string   "numero_cliente"
    t.string   "cnpj"
    t.string   "consumo_kwh"
    t.date     "vencimento"
    t.float    "valor_total",            limit: 24
    t.datetime "created_at",                        null: false
    t.datetime "updated_at",                        null: false
    t.string   "pdf_conta"
    t.string   "unidade_de_leitura"
    t.string   "cod_instalacao"
    t.string   "logradouro"
    t.string   "bairro"
    t.string   "cep"
    t.string   "municipio"
    t.string   "uf"
    t.index ["unidade_consumidora_id"], name: "index_contas_on_unidade_consumidora_id", using: :btree
  end
  

Комментарии:

1. вы не могли бы опубликовать свое определение SQL для contas таблицы? или, по крайней мере, важную часть, где valor_total определено.

2. @fanta опубликуйте правку с schema.rb … посмотрим, поможет ли это! Спасибо

3. Андрей дал вам ответ, вам нужно включить precision и scale в ваше определение.

Ответ №1:

Я почти уверен, что у вас просто «неправильный» тип базы данных.

Conta.columns_hash['valor_total'].type скорее всего, вернет "integer" , тогда как то, что вы хотите иметь, decimal если ваша цель — хранить точные числа.

Я бы рекомендовал изменить тип данных:

 change_column :contas, :valor_total, :decimal, precision: 5, scale: 2
  

Редактировать

Вы использовали float тип данных, но не указали точность. Даже если вы, вероятно (никогда не видели, чтобы float использовался тип базы данных), могли бы изменить его и указать, я бы все равно рекомендовал использовать decimal для таких целей, потому что он не выполняет никаких округлений или около того во время вычислений, поэтому у вас всегда будут самые точные цифры, которые вы можете получить.

Комментарии:

1. Это было именно то, что произошло! Сработало как по волшебству … большое спасибо!

2. @RonanLopes кроме того, обязательно проверьте, что делают presicion и scale, чтобы выбрать правильные для себя

3. Сделал это, 15 на точности отлично работает для меня. Спасибо!