Ruby Sort ActiveRecord - 浮点数存储为像浮点数一样的字符串

时间:2015-05-07 17:07:44

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 rails-activerecord

Ruby on Rails 4 - 将ActiveRecord字符串列排序为浮点数。

我有一个RecordModel表,其中包含存储版本的版本列(字符串)。版本的格式为major.minor版本。问题是版本会从9.0跳到10.0,但由于它是作为字符串存储的,我如何将其排序为整数?

RecordModel(id: integer, version: string, created_at: datetime, updated_at: datetime)

create_table "record_models", force: true do |t|
  t.string   "version"
  t.datetime "created_at",                  null: false
  t.datetime "updated_at",                  null: false
end

record_models = RecordModels.all
record_models.order(:version)

# results:
10.10
2.0
3.0

更新:   - 数据库是postgresql   - 我无法作为浮点存储,因为某些版本值为空,有些版本为x.x.x(例如1.2.3)

4 个答案:

答案 0 :(得分:2)

我没有对此进行测试,我不知道如果未成年人遗失会如何表现,但我认为值得一试。

RecordModel.all.select('*,
  split_part(version, '.', 1)::int as major,
  split_part(version, '.', 2)::int as minor,
  split_part(version, '.', 3)::int as patch'
).order(major: :desc, minor: :desc, patch: :desc)

这已更新为与postgresql一起使用

答案 1 :(得分:2)

由于您的数据库是PostgreSQL而且这是Rails4,因此您可以完全访问PostgreSQL的数组列。这意味着您可以将3.1.4之类的版本号存储为整数数组[3,1,4]。请注意,PostgreSQL数组逐个元素进行比较,因此对数组进行排序可以做正确的事情。

这样的事情:

create_table "record_models", force: true do |t|
  t.integer  "version", array: true
  #...
end

用于存储应该可以解决问题。

您仍然可以通过使用以下内容覆盖访问器和mutator方法,将它们视为输入和输出上的点分隔字符串:

def version=(v)
  super(v ? v.split('.').map(&:to_i) : nil)
end
def version
  super.to_a.join('.')
end

您可能想要进行一些额外的验证,以确保您获得您期望的格式。

如果要将版本保留为字符串,则可以使用regexp_split_to_array和类型转换根据需要将字符串转换为整数数组:

...order(%q{regexp_split_to_array(version, '\.')::int[]})

注意那里的引用,你需要将文字'\.'放入数据库,这样%q{...}可能是最干净的引用。

答案 2 :(得分:1)

您可以尝试自定义订单声明

record_models.order('CAST(records.version AS Decimal) DESC')

虽然我只是建议将版本存储为浮动

答案 3 :(得分:0)

这有效:

record_models = record_models.reorder("CAST(NULLIF(version, '') AS float) ASC")