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)
答案 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")