基于关联模型的数量查询

时间:2014-05-02 14:03:30

标签: sql ruby-on-rails postgresql activerecord scopes

我正在开展一个项目,我需要根据where子句下的关联模型数来确定模型的范围。这是我能想到的最好的:

Subscription.where('message_cap > ?', TextMessage.where('created_at > ?', DateTime.now.beginning_of_month).where(subscription: subscription).count)

但是,由于订阅未定义,因此无法正常工作。在rails查询中是否有任何方法我可以引用postgres当前被击中的模型?我认为这是我正在寻找的SQL:

SELECT * FROM 'subscriptions' WHERE 'subscription.message_cap' > (SELECT COUNT(*) FROM 'text_messages' WHERE 'text_messages.subscription_id' = 'subscription.id' AND 'text_message.created_at > BEGINNINGOFMONTH')

这是我的应用程序中真正非常重要的性能部分,所以如果可以,我需要在一个查询中运行它。

修改

顺便说一下,我不确定上面的SQL查询是否有效。我只是把它放在那里,以传达我正在寻找的想法。

2 个答案:

答案 0 :(得分:1)

尝试以下方法:

Subscription.select('subscriptions.id').
  joins(:text_messages).
  where('messages.created_at > ?', date).
  group('subscriptions.id').
  having('COUNT(*) > subscriptions.message_cap')

date作为查询的参数。

请注意,结果中的每个Subscription对象仅包含订阅的id。要检索完整对象,您需要执行以下查询:

Subscription.find(ids)

如果它是您的应用程序的关键部分,您应该使用您最喜欢的测试框架测试查询。

答案 1 :(得分:0)

query = "SELECT * FROM 'subscriptions' WHERE 'subscription.message_cap' > (SELECT COUNT(*) FROM 'text_messages' WHERE 'text_messages.subscription_id' = 'subscription.id' AND 'text_message.created_at > BEGINNINGOFMONTH')"
Subscription.find_by_sql(query)

如果这还不够快,那么您应该考虑缓存每个订阅的文本消息计数。这可以通过创建视图或向订阅表添加计数器列来完成。视图是更好的解决方案,但实施起来更多。

更新

subscriptions_table = Subscription.table_name
text_messages_table = TextMessage.table_name
foreign_key = TextMessage.reflect_on_association(:subscription).foreign_key
query = "SELECT * FROM '#{subscriptions_table}' WHERE '#{subscriptions_table}.message_cap' > (SELECT COUNT(*) FROM '#{text_messages_table}' WHERE '#{text_messages_table}.#{foreign_key}' = '#{subscriptions_table}.id' AND '#{text_messages_table}.created_at > #{Date.current.beginning_of_month}')"
Subscription.find_by_sql(query)