在一个应用程序中,我有以下模型:
class Activity < ActiveRecord::Base
has_many :activity_items, dependent: :destroy
has_many :children, through: :activity_items, source: :activity_itemable, source_type: 'Child'
has_many :parents, through: :activity_items, source: :activity_itemable, source_type: 'Parent'
...
end
ActivityItem用于将参与者添加到活动
class ActivityItem < ActiveRecord::Base
belongs_to :activity_itemable, polymorphic: true
belongs_to :activity
has_many :children, through: :activity_itemable, source_type: 'Child'
has_many :parents, through: :activity_itemable, source_type: 'Parent'
...
end
活动有一个日期列:'activity_date',其他在这里不重要。
ActityItem具有state,activity_id,activity_itemable_type和activity_itemable_id列。
我制作了一份“统计”报告,用于统计参与者(活动清单上有多少家长,有多少不同的父母在场等等)。
我构建查询来计算,但我很难理解生成的SQL,我需要帮助,以确保我正在进行良好的查询。
以下是我的一些疑问和问题:
1-我想计算我在活动中有多少不同的孩子(有孩子类型的activity_items),但仅限于2015-12-31之前的活动
Activity.where("activity_date > ?", "2015-12-31").includes(:activity_items).where("activity_items.activity_itemable_type = ?", "Child").references(:activity_items).distinct.count("activity_items.activity_itemable_id")
SQL:
SELECT DISTINCT COUNT(DISTINCT activity_items.activity_itemable_id)
FROM "activities" LEFT OUTER JOIN
"activity_items"
ON "activity_items"."activity_id" = "activities"."id"
WHERE (activity_date > '2015-12-31') AND (activity_items.activity_itemable_type = 'Child')
因为两个不同的表有两个条件,使用INNER JOIN只选择符合这两个条件的行是不合适的?
2-相同的查询,但我从另一个表开始
ActivityItem.includes(:activity).where('activity_date >= ?', "2015-01-01").where(activity_itemable_type: "Child").distinct.count(:activity_itemable_id)
同样的结果,但很少有奇怪的事情。我不得不在查询1中编写where子句。我的第一次尝试是写:
.where('activity.activity_date >= ?', "2015-01-01")
但它失败了我必须使用:
.where('activity_date >= ?', "2015-01-01")
最后奇怪的是LEFT OUTER JOIN。左边的表是activity_items,所以不应该加载这个表中的所有行吗?这就像我使用的所有查询都返回相同的结果,就像它像INNER JOIN一样。
SELECT DISTINCT COUNT(DISTINCT "activity_items"."activity_itemable_id")
FROM "activity_items" LEFT OUTER JOIN
"activities" ON "activities"."id" = "activity_items"."activity_id"
WHERE (activity_date >= '2015-01-01') AND "activity_items"."activity_itemable_type" = 'Child'
如果我使用连接而不是包含我得到了相同的结果,但使用INNER JOIN。
另一个奇怪的事情:如果我没有指定distinct而只是count(with_attribute_i_want_to_count),那么SQL仍然包含distinct。但是查询中的rails指南告诉它只有在数据库中填充给定属性时才应该计数。
我测试了我的查询,结果还可以,但我不确定如何解释和理解生成的SQL。
你如何理解这个rails例子中的LEFT OUTER JOIN?
当我在两个表上使用“includes”和条件启动查询时,我应该期待什么?
您是否有一些文件可以推荐以澄清我的情况?
感谢您阅读这个奇怪的问题!
答案 0 :(得分:1)
你有两个问题。
(1)&#34;因为两个不同的表有两个条件,使用INNER JOIN只选择符合这两个条件的行更合适吗?&#34;
内部联接也可以充当过滤器。使用left outer join
,您可以获得没有项目的活动。
(2)&#34;您如何理解此示例中的LEFT OUTER JOIN?&#34;
查询是:
SELECT DISTINCT COUNT(DISTINCT "activity_items"."activity_itemable_id")
FROM "activity_items" LEFT OUTER JOIN
"activities"
ON "activities"."id" = "activity_items"."activity_id"
WHERE (activity_date >= '2015-01-01') AND "activity_items"."activity_itemable_type" = 'Child'
-------------------------------------------^
查询的注释部分是left outer join
中第二个表的条件。这会将left outer join
变为inner join
。
故事的寓意:不要使用代码生成器来尝试理解SQL。它们产生非常具体的代码,可能与人们生产的代码完全不同。例如,两个查询中distinct
完全没有select distinct
。这两个查询都不使用表别名,这会提高可读性。并且识别都是逃脱的,可能特别是为了阻止人类理解它们。