【问题标题】:What is difference between selecting users.* and selecting each individual columns?选择 users.* 和选择每个单独的列有什么区别?
【发布时间】:2015-04-02 09:18:42
【问题描述】:

我正在研究 Ruby on Rails,并且有一些关于 Rails 活动记录及其 SQL 转换的具体问题。

仅供参考,我使用的是 postgresql,而 user 模型有许多 statuses,我想根据 订购 users statuses 的 created_at 列。虽然我找到了解决方案,User.includes(:statuses).order('statuses.created_at desc'),但我仍然有一些(可能是相互关联的)我不太了解的东西。

1) 在 Rails 控制台上,(为了更好的可读性,我进行了简化)

User.joins(:statuses).to_sql 产生"SELECT users.* FROM users INNER JOIN statuses ON statuses.user_id = users.id"。

User.includes(:statuses).references(:statuses).to_sql 产生"SELECT users.id AS t0_r0, ...(simplified)... statuses.created_at AS t1_r3 FROM users LEFT OUTER JOIN statuses ON statuses.user_id = users.id"

选择 users.* 和选择每个单独的列有什么区别?

2) 也在 Rails 控制台上,

User.joins(:statuses).size 产生SELECT COUNT(*) FROM users INNER JOIN statuses ON statuses.user_id = users.id => 155。

User.includes(:statuses).references(:statuses).size 产生SELECT COUNT(DISTINCT users.id) FROM users LEFT OUTER JOIN statuses ON statuses.user_id = users.id => 16。

为什么 includes 自动包含 distinct 子句而 joins 不包含?

3) 我试图获得由 statuses.created_at 排序的不同 users,并在 users 上加入了 statuses .

我使用了这个子句:User.joins(:statuses).select('users.*, statuses.created_at').order('statuses.created_at desc').distinct。 (由于PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list,我应该使用select statuses.created_at)

但是这个子句并没有删除重复!虽然User.joins(:statuses).select!('users.*, statuses.created_at').order('statuses.created_at desc').distinct.size 产生了16,但当我实际执行它时,我看到了很多重复。

生成SQL语句:SELECT DISTINCT users.*, statuses.created_at FROM users INNER JOIN statuses ON statuses.user_id = users.id ORDER BY statuses.created_at desc,并显示如下图。

Result of User.joins(:statuses).select!('users.*, statuses.created_at').order('statuses.created_at desc').distinct

如您所见,它显示了我的记录的重复。

所以我的第三个问题是,为什么 distinct 子句不删除重复项(以及为什么 size 显示不同的结果)?

提前谢谢你!

【问题讨论】:

    标签: ruby-on-rails postgresql join include distinct


    【解决方案1】:

    joins 方法只是为您生成一个 SQL 连接。任何个人用户都可以加入多个状态 - 这正是加入的作用,如果这不是您需要的,那么由您来处理它。 select 子句默认为users.*,这样您就不会在不知情的情况下在两个表中出现相同名称的列相互影响(例如id 列)

    includes 另一方面用于急切加载关联。这有时是通过连接来完成的,这只是一个实现细节——在处理结果时有额外的代码,以便结果集只包含每个用户一次(并且将状态数据输入到关联中)。还包括别名所有列名以处理同名列

    最后,您的 distinct 子句不会删除重复项,因为行不相同 - 包括 statuses.created_at 列,这在大多数行中会有所不同。

    size 方法会忽略您的 select 子句,因此计入 users.id - 在这种情况下, distinct 只会将每个用户计入一次

    【讨论】:

    • 我登录 Stackoverflow 提出问题,并意识到我在 3 年前提出了一个问题。虽然已经很晚了,但感谢@Frederick 的真诚回复。
    猜你喜欢
    • 2012-11-14
    • 1970-01-01
    • 2014-06-04
    • 2012-06-01
    • 2011-09-02
    • 1970-01-01
    • 2011-08-02
    • 2013-06-27
    • 1970-01-01
    相关资源
    最近更新 更多