![](/img/trans.png)
[英]ActiveRecord: complex query with Sum, Join, Group By and Select multiple fields
[英]Rails ActiveRecord friendly code from a Complex Join, Sum, and Group query
问题
你好,
我没有运气试图将此SQL语句分解为ActiveRecord / Rails友好代码,并且我想学习在这种情况下如何避免使用find_by_sql语句。
方案我有一些用户在执行操作时创建审核。 每次审核都具有特定的audit_activity。 根据score_weight,每个audit_activity都值一定数量的分数。 我需要根据每个用户的累计audit_activity score_weights总数来找到总得分。 最终,我需要对它们进行排名,这也意味着要对其进行排序。
我的代码这里是有关表的sql和简化版本。 有什么想法吗?
具有完整列名的SQL(为清楚起见)
SELECT users.id, u.email, SUM(audit_activity.score_weight)
FROM users
JOIN audits ON users.id = audits.user_id
JOIN audit_activities ON audit_activities.id = audits.audit_activity_id
GROUP BY users.id;
型号:用户,审计,AuditActivity
用户字段:ID,电子邮件
class User < ActiveRecord::Base
include Clearance::User
has_many :audits
end
审核字段:id,user_id,audit_activity_id
class Audit < ActiveRecord::Base
belongs_to :user
belongs_to :audit_activity
end
AuditActivity字段:id,score_weight
class AuditActivity < ActiveRecord::Base
has_many :audits
end
示例数据
这是一组SQL语句,因此您可以处理正在使用的类似数据,并查看运行相关查询时发生的情况。 您应该只能够将整个内容复制/粘贴到数据库查询浏览器中。
CREATE TABLE users(
id INTEGER NOT NULL,
email TEXT (25),
PRIMARY KEY (id)
);
CREATE TABLE audits(
id INTEGER NOT NULL,
user_id INTEGER,
audit_activity_id INTEGER,
PRIMARY KEY (id)
);
CREATE TABLE audit_activities(
id INTEGER NOT NULL,
score_weight INTEGER,
PRIMARY KEY (id)
);
INSERT INTO users(id, email)
VALUES(1, "1user@a.com");
INSERT INTO users(id, email)
VALUES(2, "2user@b.com");
INSERT INTO users(id, email)
VALUES(3, "3user@c.com");
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(1, 1, 1);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(2, 1, 2);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(3, 1, 1);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(4, 1, 3);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(5, 1, 1);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(6, 1, 4);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(7, 2, 4);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(8, 2, 4);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(9, 2, 4);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(10, 3, 3);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(11, 3, 2);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(12, 3, 2);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(13, 3, 2);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(14, 3, 3);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(15, 3, 1);
INSERT INTO audits(id, user_id, audit_activity_id)
VALUES(16, 3, 1);
INSERT INTO audit_activities(id, score_weight)
VALUES(1, 1);
INSERT INTO audit_activities(id, score_weight)
VALUES(2, 2);
INSERT INTO audit_activities(id, score_weight)
VALUES(3, 7);
INSERT INTO audit_activities(id, score_weight)
VALUES(4, 11);
再次查询 ,这是查询。
SELECT u.id, u.email, SUM(aa.score_weight)
FROM users u
JOIN audits a ON u.id = a.user_id
JOIN audit_activities aa ON aa.id = a.audit_activity_id
GROUP BY u.id;
User.sum( :score_weight, :include => {:audits => :audit_activity}, :group => 'users.id' )
吸引用户非常容易,并遍历每个用户的审核,在您进行操作时汇总值。 所以会是这样的:
users = User.find(:all) users.each do |user| puts "user: #{user.email}" score = 0 user.audits.each do |audit| puts " audit: #{audit.audit_activity.id} score: #{audit.audit_activity.score_weight}" score += audit.audit_activity.score_weight end puts "total score for this user: #{score" end
但是,这将生成许多单独的查询,但这并不总是一件坏事。
如果数据量将很大,并且正如您所说,您将要按用户得分排序,那么我认为答案将是在用户记录上包含一个具有当前得分的字段,该字段每次更新时都会更新审核活动记录已写入。 这可以通过关联回调(即,用户记录上的审核关联上的after_add方法)自动完成。 请参阅http://guides.rubyonrails.org/association_basics.html#association-callbacks 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.