Rails 4 / postgresql - 将数据发送到另一个表的另一个随机选择的行

时间:2015-09-17 20:10:26

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

我有一个Ruby on Rails 4应用程序和postgresql9.4作为数据库。

我有DealDealPrizePrize型号。

奖品有数量和名称。例如,prize1的名称为dvd,数量为67DealPrize有一列deal_idprize_id

class Deal
  has_many :prizes, dependent: :destroy   
  has_many :deal_prizes, dependent: :delete_all
end

class Prize
  belongs_to :deal, :foreign_key => 'deal_id'
  has_many   :deal_prizes,  dependent: :destroy  
end

class DealPrize
  belongs_to :deal,  :foreign_key => 'deal_id'       
  belongs_to :prize, :foreign_key => 'prize_id'
end

数据库结构:

create_table "deal_prizes", id: :bigserial, force: :cascade do |t|
    t.string   "name",                    
    t.integer  "deal_id"
    t.integer  "prize_id"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
end

create_table "prizes", force: :cascade do |t|
    t.string   "prize_name",         limit: 255
    t.integer  "quantity"
    t.integer  "deal_id"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false    
end

add_index "prizes", ["deal_id"], name: "index_prizes_on_deal_id", using: :btree


create_table "deals", force: :cascade do |t|
    t.string   "name",          limit: 255
    t.string   "description",   limit: 255    
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false   
end

我会举一个例子来解释我想要的东西,但到目前为止还没有实现:

  • 我需要选择与Deal id = 5相关联的所有奖品。 例如,我会得到结果 奖品ID = 5 => DVD(其奖金数量= 67) 奖品ID = 9 => Cd(其prize.quantity = 32)

  • 然后在DealPrizes行中的随机选定行中发送这些奖品(即67张DVD和7张CD),其中Deal_id = 5 AND prize_id =空(需要这样,如果它已被归为奖品,则不应再将其他奖项放在同一行内)

注意:我不想找到它们并写入连续的行:我需要随机行。

  • 然后写入随机选择的行这些Dealprizes。所以我会写67个随机选择的行prize_id = 5和9个随机选择的行prize_id = 9

注意: DealPrize中的行数优于2百万,因此需要性能。 我宁愿使用原始sql 而不是活动记录,并且会尝试不直接在整个表格上使用Rand和随机函数像这样的家伙建议不要http://www.adamwaselnuk.com/projects/2015-03-28-here-be-taverns.html < / p>

  

“问题是这些可能会导致较大的表格出现性能问题   因为当你说“嘿数据库随机排序表然后   给我第一排“桌子说”好的,我要经历   每一行并为其分配一个随机数,然后限制我的   选择一个“。要求一件事导致计算   表格中的每一行!“

我是Rails的新手所以我只能解释/映射模型/ deal.rb所需的不同步骤

# 1. find the first prize where deal_id= seld.id
# and take each of the prizes quantity and id ofr the next steps
def find_prizes_for_this_deal
  Prize.find_by deal_id: self.id  # here I could only find one, don't know how to find many prizes at once and keep both id and quantity
end

# 2. choose Deal prize's table randomly chosen rows (created for the same
# deal attached to prizes) where deal_id=self.id and prize_id = empty    
def DealPrize.random
  # trick found here http://www.adamwaselnuk.com/projects/2015-03-28-here-be-taverns.html, in order not to use the poor-performance rand() methodon the whole table
  offset(rand(count)).first.where(["deal_id = ?", self_id] && prize_id= nil)
end

#3. send the prizes selected in step 1. into the randomly chosen rows of 
# DealPrizes in step 2
def NO IDEA here how to do this at
end

如何使这项工作?

2 个答案:

答案 0 :(得分:1)

你的问题非常复杂,让我很困惑。我们一步一步走吧。

  

我需要选择与Deal id = 5相关联的所有奖品。

这很容易。

ListView

答案 1 :(得分:1)

这个问题需要做很多事情。我可以帮助你最多,并指出你正确的方向。

第一部分已被回答

<pre><code>deal = Deal.find(5)
prizes = deal.prizes
</code></pre>

您可以循环浏览奖品



    prizes.each do |prz|
      d_id = prz.deal_id
      p_id = prz.id
      quantity_count = prz.quantity
    end

获得一等奖的数量

quantity_count = prizes[0].quantity

或者通过身份证获得一个奖项

prz = prizes.where(id: 5)

我建议创建两个新数组,用于存储随机数,以便在查询中使用。从deal_prizes获取最后一个记录ID作为您的最大号码。

max = DealPrize.order("id").last.id

根据数量计数,循环以使用随机数填充数组

first_prize = []
(1..quantity_count).each do |n|
   first_prize << rand(max)
end

您可以使用该数组查找或更新记录

DealPrize.where(id: first_prize).update_all(deal_id: d_id, prize_id: p_id)

或者如果您要对其进行硬编码

"UPDATE deal_prizes SET deal_id = #{d_id}, prize_id = #{p_id} WHERE id IN ( #{first_prize.join(',')} )"

请注意更新记录,其中prize_id不为null或为零(但是您指明它)。您可以运行查询,直到找到67条记录,其中prize_id为空。

good_rows = DealPrize.where(id: first_prize).where("prize_id IS NULL")
bad_rows = first_prize - good_rows

然后通过随机生成新的ID并再次查询来替换bad_rows中的id。继续这样做,直到找到所有好的行,然后通过添加现有的perfect_first_prize = good_rows + new_good_rows

新的好行来更新