- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
处理以下 8 个不同 SQL 问题的最佳方法是什么。
我在数据库模式下放置了它,它是如何在我的 Rails 模型中表示的,以及我需要从数据库中获取数据的七个问题。我已经回答了一些问题,其他问题我不确定最好的解决方案。
问题#7 是一个曲线球,因为它可能会改变所有其他问题的答案。
标准
Students-------IDNameCourses-----IDNameGradeEnrollments----------IDStudent_IDCourse_ID
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, :through=>:enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
end
class Student < ActiveRecord::Base
has_many :enrollments
has_many :courses, :through => :enrollments
end
SELECT s.* FROM Students s
LEFT JOIN Enrollments e on e.student_id = s.id
LEFT JOIN Courses c on e.course_id = c.id
WHERE c.grade = 9 AND c.name = 'Math'
c = Course.where(:grade=>9).where(:name=>'Math').first
c.students
SELECT c.* FROM Courses c
LEFT JOIN Enrollments e on c.id = e.course_id
LEFT JOIN Students s on e.student_id = s.id
WHERE s.name = 'John'
s = Student.where(:name=>'John').first
s.courses
SELECT c.*, count(e.student_id) FROM Courses C
LEFT JOIN Enrollments e on c.id = e.course_id
WHERE c.grade = 9 GROUP BY c.id
class AddCounters < ActiveRecord::Migration def up add_column :students, :courses_count, :integer, :default=>0 add_column :courses, :students_count, :integer, :default=>0 Student.reset_column_information Student.all.each do |s| Student.update_counters s.id, :courses_count => s.courses.length end Course.reset_column_information Course.all.each do |c| Course.update_counters c.id, :students_count => c.students.length end end def down remove_column :students, :courses_count remove_column :courses, :students_count endend
ActiveRecord
Course.where(:grade=>9).each do |c| puts "#{c.name} - #{c.students.size}"end
Not sure of the best solution. This would be VERY messy to do in SQL without keeping a counter cache for number of courses per grade level on each student. I could add a hook to update this information myself. I don't want to pull all students and courses and count them in post processing.
The following solution produces a lot of queries. Preloading the courses may not be possible. (For example, the students are coming from the association on a course)
students = some_course.students
matching_students = []
students.each do |s|
courses_9 = 0
courses_10 = 0
courses_11 = 0
s.courses.each do |c|
courses_9 += 1 if c.grade == 9
courses_10 += 1 if c.grade == 10
courses_11 += 1 if c.grade == 11
end
if courses_11 <= 3 && courses_10 > 1 && courses_9 == 0
matching_students << s
end
end
return matching_students
SELECT s.*, count(e.course_id) as num_Courses FROM Students s
INNER JOIN Enrollments e on s.id = e.student_id
INNER JOIN Courses c on e.course_id = c.id AND c.name = 'Math'
GROUP BY s.id HAVING num_Courses > 0
SELECT DISTINCT s.* FROM Students s
INNER JOIN Enrollments e_math_1 on e_math_1.student_id = s.id
INNER JOIN Courses c_math_1 ON e_math_1.course_id = c_math_1.id AND c_math_1.name = 'Math'
INNER JOIN Enrollments e_math_2 on e_math_2.student_id = s.id
INNER JOIN Courses c_math_2 ON e_math_2.course_id = c_math_2.id AND c_math_2.name = 'Math'
WHERE c_math_1.id != c_math_2.id
students = SomeObject.students
multiple_math_course_students = []
students.each do |s|
has_math_course = false
add_student = false
s.courses.each do |c|
if c.name == 'Math'
if has_math_course
add_student = true
else
has_math_course = true
end
end
end
multiple_math_course_students << s if add_student
end
SELECT s.* FROM Students s
INNER JOIN Enrollments e_math on e_math.student_id = s.id
INNER JOIN Courses c_math ON e_math.course_id = c_math.id
INNER JOIN Enrollments e_science on e_science.student_id = s.id
INNER JOIN Courses c_science on e_science.course_id = c_science.id WHERE c_math.name = 'Math' AND c_science.name = 'Science'
students = SomeObject.students
math_and_science_students = []
students.each do |s|
has_math_course = false
has_science_course = false
s.courses.each do |c|
has_math_course = true if c.name == 'Math'
has_science_course = true if c.name == 'Science'
end
math_and_science_students << s if has_math_course && has_science_course
end
最佳答案
首先,我认为您的数据库架构很好。我不会基于这些用例去规范化,因为它们很常见。
其次,你必须学会区分持久化、业务逻辑和报告。 ActiveRecord 有利于基本的持久化和封装业务逻辑。它处理 CRUD 的内容,并允许您将应用程序的许多逻辑放入模型中。但是,您所谈论的许多逻辑听起来像是报告,尤其是#6。您将不得不接受这样的查询逻辑,原始 SQL 将是您最好的选择。我认为您实现的缓存计数器可能会帮助您保持事件记录和模型,如果您在那里更舒服,但很可能您将不得不像对其中几个解决方案所做的那样降到普通 sql。报告一般需要直接的 sql。
规范化的数据库对于良好的应用程序设计至关重要。它对于使 OLTP 事务和业务逻辑的代码干净非常重要。不要仅仅因为你必须在 sql 中做一些连接而去规范化。这就是 sql 擅长的地方。通过非规范化你要做的就是让你的一些报告逻辑更快更容易,代价是让你的持久性和 OLTP 逻辑变得更慢和更难。
所以我会开始保留你的规范化数据库。如果您需要加入相关表,您通常可以使用 activerecord 的 include 方法来执行此操作,而无需求助于常规 sql。要执行基于连接的计数之类的操作,您必须使用普通的 sql。
最终,如果您的数据库变得非常大并且包含大量数据,您的报告将由于您必须执行的所有连接而变慢。这可以。在那一点上,立即开始考虑制作一个单独的非规范化报告数据库,您可以每小时、每晚、每周等从规范化数据库中更新。然后移动您的报告逻辑以查询报告数据库,而无需进行联接。然而,没有必要以这种方式开始。您只会招致额外的复杂性和费用,而无法确定返回。也许您的带有连接的报告 sql 将无限期地工作,而无需使用索引进行非规范化。不要过早地优化。
我认为 nosql 也不一定是答案。据我所知,NoSQL 适用于特定用例。您的应用程序的用例和架构似乎非常适合关系数据库。
总的来说,我认为原始 sql(不是 arel/activerecord)和你实现的计数器的组合很好。
关于ruby-on-rails - ActiveRecord - 非规范化案例研究,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12271532/
这个问题在这里已经有了答案: Oracle: merging two different queries into one, LIKE & IN (1 个回答) 8年前关闭。 我有以下代码: case
我查阅过此页面:http://dev.mysql.com/doc/refman/5.1/en/case.html以及这个,但无法获得一个简单的程序来工作...... 更新:为了明确我想要做什么:我想从
有什么办法可以优化下面的查询吗? SELECT DATE_FORMAT(a.duedate,'%d-%b-%y') AS dte, duedate, SUM(CASE WHEN (typeofnoti
我进退两难,以下 SQL 查询的结果是什么以及它是如何工作的: SELECT ... CASE WHEN (a.FIELD=1 AND b.FIELD=2) THEN 1 WHEN
问题:输入年,月,打印对应年月的日历。 示例: 问题分析: 1,首先1970年是Unix系统诞生的时间,1970年成为Unix的元年,1970年1月1号是星期四,现在大多的手机的日历功能只能显
**摘要:**介绍了Angular中依赖注入是如何查找依赖,如何配置提供商,如何用限定和过滤作用的装饰器拿到想要的实例,进一步通过N个案例分析如何结合依赖注入的知识点来解决开发编程中会遇到的问题。 本
我想拥有自动伴侣类apply case 类的构造函数来为我执行隐式转换,但无法弄清楚如何这样做。我到处搜索,我能找到的最接近的答案是 this问题(我将解释为什么它不是我在下面寻找的)。 我有一个看起
您好,我已经浏览了“多列案例”问题,但没有看到与此相同的内容,所以我想我应该问一下。 基本上我有两个我想要连接的表(都是子查询的结果)。它们具有相同的列名称。如果我加入他们的 ID 和 SELECT
我发现了一些类型推断的非直觉行为。因此,语义等效代码的工作方式不同,具体取决于编译器推断出的有关函数返回类型的信息。当您在最小单元测试中重现此案例时,或多或少会清楚发生了什么。但我担心在编写框架代码时
CREATE TABLE test ( sts_id int , [status1] int , [status2] int , [status3] int , [status4] int ) INS
我有以下声明: SELECT Dag AS Dag, CASE Jaar WHEN 2013 THEN Levering END AS '2013', CASE
我想做的是为所有高于平均时间、平均时间和低于平均时间的游乐设施获取平均tip_portion。所以返回3行。当我运行它时,它显示: ERROR: missing FROM-clause entry
我正在尝试设置一个包含以下字段的报告: 非常需要报告来显示日期、该日期内的总记录(因此我按日期分组),然后按小时计算 12 小时工作日(从上午 8 点到晚上 8 点)我需要计算记录在这些时间内出现的时
我有这个查询 SELECT users.name FROM users LEFT JOIN weapon_stats ON users.id = weapon_stats.zp_id WHERE we
我正在尝试按收视率等级获取不同视频的计数。我有下表: vid_id views 1 6 1 10 1 900 2 850 2 125000
假设我有一个如下所示的 SQL 语句: select supplier, case when platform in (5,6) then 'mobile' when p
我有一个表测试 TestNumber (int primary key) InactiveBitwise (int) 我执行以下命令: UPDATE tests SET CASE WH
我有一个像这样的表(name=expense): id amount date 1 -1687 2014-01-02 00:00:00.0 2 11000 2014-01-02 0
我有一个 multimap 定义 typedef std::pair au_pair; //vertices typedef std::pair acq_pair; //ch qlty specifi
我有一个有点像枚举的类,它的每个实例都有一个唯一的 int 值,该值从 0 开始并在每个新实例时递增。 class MyEnumLikeClass { static int NextId =
我是一名优秀的程序员,十分优秀!