我有一个Ruby on Rails 4应用程序和postgresql9.4作为数据库。
我有Deal
,DealPrize
和Prize
型号。
奖品有数量和名称。例如,prize1
的名称为dvd
,数量为67
。
DealPrize
有一列deal_id
和prize_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 =空(需要这样,如果它已被归为奖品,则不应再将其他奖项放在同一行内)
注意:我不想找到它们并写入连续的行:我需要随机行。
注意: 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
如何使这项工作?
答案 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