繁体   English   中英

来自复杂联接,求和和组查询的Rails ActiveRecord友好代码

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM