mysql - 如何动态比较连接表与源

标签 mysql ruby-on-rails ruby activerecord arel

背景

我有五个模型:Reward、BrandSubscription、Brand、Tier 和 User。

  • Brand 有很多 Tiers
  • BrandSubscription 属于 TierUser
  • Reward 属于一个Tier
  • Tier 有一个名为 order 的属性。如果 BrandSubscription 具有更高级别的层级,那么它也将具有所有较低层级。
  • BrandSubscription 可以看到来自其所有 Tiers 的所有 Rewards,在本例中是 Tier它属于及其所有较低的 Tiers

问题

我的问题是上面列表的最后一项。我正在尝试获得品牌订阅的所有奖励。

理想的方式是 BrandSubscription 实体上的 has_many :rewards,即 through::tier。在 Tier 上,我可以有一个 has_many :rewards。这种方法的问题是奖励不限于当前层,而是必须包括来自较低 order 层的所有奖励。

为了实现这一点,我在 Tier 模型的 has_many :rewards 上设置了一个范围:

class Tier < ActiveRecord::Base
  belongs_to :brand
  has_many :rewards

  has_many :with_lower_tiers, lambda {
    where(this_table[:order].gteq(that_table[:order]))
  }, through: :brand, source: :tiers

  has_many :achievable_rewards, through: :with_lower_tiers, source: rewards
end

这里的问题在于 this_tablethat_table。我需要在这里进行某种连接,这样我就可以在表之间进行比较。我可以采用的一种方法是:

class Tier < ActiveRecord::Base
  belongs_to :brand
  has_many :rewards

  has_many :with_lower_tiers, lambda { |tier|
    where(current_scope.table[:order].lteq(tier.order))
  }, through: :brand, source: :tiers

  has_many :achievable_rewards, through: :with_lower_tiers, source: rewards
end

这里我使用层所有者对象并获取其顺序。这里的问题是我不能真正依赖 tier 参数。下面的查询已经中断,因为真正作为参数传递给范围函数的是查询的“所有者”实体,在本例中为 BrandSubscription:

BrandSubscription.joins(:with_lower_tiers)

我想要获取的 SQL 查询如下,我可以从中获取用户的所有可用奖励。请注意,我加入了 tiers 表两次,这正是我遇到麻烦的地方:

SELECT DISTINCT rewards.*
  FROM tiers
  INNER JOIN brand_subscriptions ON tiers.id = brand_subscriptions.tier_id
  INNER JOIN tiers tiers_reward ON tiers_reward.brand_id = tiers.brand_id
  INNER JOIN rewards ON tiers_reward.id = rewards.tier_id
  WHERE tiers_reward.order <= tiers.order
    AND brand_subscriptions.user_id = 1234

我相信一些 Arel 可能会有所帮助,但如果我可以完全依赖 ActiveRecord,我真的会很高兴,因为代码会更清晰。

引用资料

我正在使用以下链接来尝试解决此问题:

最佳答案

您可以自己构建查询而不是依赖复杂的 has_many-through 关联

class Reward < ActiveRecord::Base
  belongs_to :tier
end

class Brand < ActiveRecord::Base
  has_many :tiers
end

class Tier < ActiveRecord::Base
  belongs_to :brand
  has_many :rewards

  # has_many :lower_tiers, ->(tier){ where('tiers.order < ?', tier.order) }, through: :brand, source: :tiers

  def lower_tiers
    Tier.where('brand_id = ? AND order < ?', brand_id, order)
  end

  def achievable_rewards
    Rewards.where('tier_id IN (?) OR tier_id = ?', lower_tiers.select(:id), id)
  end
end


class BrandSubscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :tier

  def rewards
    tier ? tier.achievable_rewards : Reward.none
  end
end

关于mysql - 如何动态比较连接表与源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34416722/

相关文章:

sql - 从列表中为每个帐户 ID 获取一行,第 2 部分

ruby-on-rails - Ruby 中有效子域的正则表达式

ruby-on-rails - Sidekiq 和 Puma 中的 Redis 变量,线程安全吗?

php - 如何在 PHP 中回显不同的计数?

mysql - 错误 #1159 与 MySQL FEDERATED 表和一种查询

ruby-on-rails - 验证多个中至少一个的存在

ruby-on-rails - Ruby on Rails 中的 yield 似乎在渲染时增加了额外的空间

ruby-on-rails - 尝试使用 Regex 验证模型中的字段。适用于 Rubular 但不适用于我的验证

ruby - 为什么 ruby​​ 语言中哈希的重复键不返回错误?

php - 有条件的 mysql rand