我有一个查询,在USER表中查找根据其联属代码的频率查找前9个分支机构。
affs = User.group(:affiliate).limit(9).count.sort_by{|i,j|-j}
(0.6ms) SELECT COUNT(*) AS count_all, affiliate AS affiliate FROM "users" GROUP BY affiliate LIMIT 9
#=> [["ACE5", 5], ["2YY", 3], ["MB7", 2], ["GB2", 2], ["GHCYM", 1], ["L6EOC", 1], ["15F2", 1], ["R0TK", 1], ["DSB", 1]]
现在我接受这个结果并在其上枚举以获得与用户对应的行。
affs.map do |aff|
user = User.find_by(qcode: aff.first)
[user.avatar.url(:thumb), user.name.match(/\w*/)[0], aff.first, aff.last]
end
#LOG OUTPUT
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'ACE5' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = '2YY' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'GB2' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'MB7' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'L6EOC' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = '15F2' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'R0TK' LIMIT 1
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."qcode" = 'DSB' LIMIT 1
运行此查询9次似乎非常多余。如何将其优化为1或2个数据库查询?
示例USERS表DB模式:
id | email | name | qcode | affiliate
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 | kjones@aol.com | Ken Lu | DSB | L6EOC
26 | broks2@aol.com | Brains Bruk | AJ8U | DSB
27 | joanshu@aol.com | Joan Hu | K9UE | DSB
从上面的例子。 " Ken Lu"是联属会员DSB
,他负责注册ID 26和ID 27.因此上述aff
查询将产生:
#=> [["DSB", 2], ...]
答案 0 :(得分:1)
要一次获取所有9个关联企业的user
表信息,您可以直接进入原始SQL。
从我上面的代码中我可以推断出你的模式,这样的东西应该有效(如果你的模式与我推断的不同,你可能需要调整一下;没有测试,因为我没有你的数据也没有 Rails 设置方便):
WITH top_affiliates AS
(
SELECT COUNT(*) AS count_all, affiliate AS affiliate
FROM users
GROUP BY affiliate
ORDER BY count_all
LIMIT 9
)
SELECT *
FROM top_affiliates AS t
JOIN users AS u ON (t.affiliate = u.qcode)
ORDER BY count_all
请注意,JOIN
假定t.affiliate = u.qcode
将在表之间提供唯一的映射(基于从迭代地图时得到的SQL,这似乎是一个公平的假设)。但是,如果它不是唯一的,则需要在JOIN
中添加其他参数,使得映射是唯一的,否则您将在结果中获得您不想要的其他行。
如果您正在使用 ActiveRecord ,则可以在包含此信息的模型上使用connection.execute
,并将上述SQL作为字符串传递(或者首先将它分配给变量并将其传递给。)。
根据OP的评论进行编辑:
@ f1f5:WITH
查询定义了所谓的 CTE ,它本质上是一个限定为查询本身而不是连接的临时表。然后我可以在WITH
下面的查询中使用 CTE ,这就是我上面所做的。基本上,WITH
查询取代了您的User.group(:affiliate).limit(9).count.sort_by{|i,j|-j}
代码,然后使用内联结果来提取相关的user
记录。
编辑以响应来自OP的架构信息:
所以,是的,我认为上面的代码会做你想要的。这是我使用架构数据,查询和结果创建的sqlfiddle。