首页 > 解决方案 > 在范围内生成连续的唯一编号

问题描述

我的数据库中有一个字段来保存一个唯一的数字,添加 created_at 年份的最后两位数字。目前一切正常,除了使用 SecureRandom 方法之外,我正在寻找保存连续数字的选项。IE。1901、1902、1903……

模型

before_create :create_number

def create_number
    loop do
      self. number = ((created_at + 1.year).strftime("%y")).concat(sprintf '%02d', SecureRandom.random_number(200))
      break unless self.class.exists?(:number => number)
    end
  end

标签: ruby-on-railsruby-on-rails-5

解决方案


关键是使用计数查询获取特定年份的记录计数:

class Thing < ApplicationRecord

  before_commit :create_number!, if: -> { number.nil? }

  private

  def count_records_from_same_year
    self.class.where(
      created_at: (created_at.beginning_of_year..created_at.end_of_year)
    ).count
  end

  def create_number!
    loop do
      year = (created_at + 1.year).strftime("%y")
      self.number = year.concat(sprintf '%02d', count_records_from_same_year)
      break unless self.class.where(number: self.number).exists?
    end
  end
end

如您所见,它会生成连续的数字:

irb(main):001:0> Thing.create
   (0.3ms)  BEGIN
  Thing Create (1.3ms)  INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2018-10-12 09:57:24.527527"], ["updated_at", "2018-10-12 09:57:24.527527"]]
   (1.2ms)  SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2  [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
  Thing Exists (1.4ms)  SELECT  1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2  [["number", "1901"], ["LIMIT", 1]]
   (0.7ms)  COMMIT
=> #<Thing id: 1, number: "1901", created_at: "2018-10-12 09:57:24", updated_at: "2018-10-12 09:57:24">
irb(main):002:0> Thing.create
   (0.3ms)  BEGIN
  Thing Create (0.8ms)  INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2018-10-12 09:57:26.402797"], ["updated_at", "2018-10-12 09:57:26.402797"]]
   (0.7ms)  SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2  [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
  Thing Exists (0.8ms)  SELECT  1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2  [["number", "1902"], ["LIMIT", 1]]
   (0.7ms)  COMMIT
=> #<Thing id: 2, number: "1902", created_at: "2018-10-12 09:57:26", updated_at: "2018-10-12 09:57:26">
irb(main):003:0> Thing.create
   (0.5ms)  BEGIN
  Thing Create (0.7ms)  INSERT INTO "things" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2018-10-12 09:57:27.537635"], ["updated_at", "2018-10-12 09:57:27.537635"]]
   (1.6ms)  SELECT COUNT(*) FROM "things" WHERE "things"."created_at" BETWEEN $1 AND $2  [["created_at", "2018-01-01 00:00:00"], ["created_at", "2018-12-31 23:59:59.999999"]]
  Thing Exists (0.6ms)  SELECT  1 AS one FROM "things" WHERE "things"."number" = $1 LIMIT $2  [["number", "1903"], ["LIMIT", 1]]
   (0.7ms)  COMMIT
=> #<Thing id: 3, number: "1903", created_at: "2018-10-12 09:57:27", updated_at: "2018-10-12 09:57:27">

推荐阅读