了解查询(包括,连接,条件)

时间:2014-02-28 01:36:45

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

在一个应用程序中,我有以下模型:

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”和条件启动查询时,我应该期待什么?

您是否有一些文件可以推荐以澄清我的情况?

感谢您阅读这个奇怪的问题!

1 个答案:

答案 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。这两个查询都不使用表别名,这会提高可读性。并且识别都是逃脱的,可能特别是为了阻止人类理解它们。