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

What is difference between selecting users.* and selecting each individual columns?

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

仅供参考,我正在使用 postgresql,user 模型有很多 statuses,我想订购 users 基于 created_at 列的 statuses。虽然我找到了解决方案,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"

selecting users.* 和 selecting 每个单独的列之间有什么区别?

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) 我试图获得不同的 usersstatuses.created_at 排序,statuses 加入 用户.

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

但是这个子句并没有删除重复!虽然 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 显示不同的结果)?

提前致谢!

joins 方法只会为您生成一个 SQL 连接。任何个人用户都可以加入多个状态 - 这正是加入所做的,如果这不是你需要的,那么由你来处理它。 select 子句默认为 users.* ,这样您就不会无意中在两个表中得到相同名称的列并相互遮蔽(例如 id 列)

另一方面,

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

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

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