假设我有这些模型:
Student:
string name
list<Subject> enrolledCourses
Subject:
string name
integer credits
我可以将其存储在数据库中的方式是:
CREATE TABLE student(
id serial PRIMARY KEY,
student_subject_mapping int NOT NULL,
name character varying
);
CREATE TABLE student_subject_mapping(
id serial PRIMARY KEY,
student_id int,
subject_id int
);
CREATE TABLE subject(
id serial PRIMARY KEY,
name character varying,
credits int
);
要获取学生(伪代码),我可以这样做:
var student = SELECT * FROM student WHERE id = ?id;
var subjects = SELECT * FROM subject WHERE id IN (SELECT * FROM student_subject_mapping WHERE student_id = ?student['id']);
make_student(student, subjects)
或者,我可以这样做:
var student = SELECT * FROM student INNER JOIN student_subject_mapping
ON student.id = student_subject_mapping.student_id INNER JOIN subject
ON subject.id = student_subject_mapping.subject_id;
以上将返回该类型的行(为简洁省略一些列):
+--------------+-------------------+
| student.name | subject.name |
+--------------+-------------------+
| Rohan | Physics |
| Rohan | Biology |
| Rohan | Computer Science |
+--------------+-------------------+
在这种情况下,我可以从任何行获取student
部分的信息,并通过迭代其他行来获取主题。这可能听起来有点复杂,但对我来说这很简单,因为我使用jooq:
Result<Record> rows = query.execute();
if (rows.size() > 0) {
StudentRecord student = rows.get(0).into(Tables.STUDENT);
}
List<SubjectRecord> subjects = rows.stream()
.map(x -> x.into(Tables.SUBJECT))
.collect(Collectors.toList());
但我不确定这是否是正确的方法。如果subject
类似于:
Subject:
string name
list<Department> offeringDepartments
我知道这是一个不好的例子,因为subject
可能不应该存储有关提供部门的信息,但请一起玩,因为我相信你可以看到模型可能有多层嵌套。在这种情况下,不仅我的查询变得复杂,我有类型的行:
+--------------+-------------------+------------------+
| student.name | subject.name | departments.name |
+--------------+-------------------+------------------+
| Rohan | Physics | Science |
| Rohan | Biology | Science |
| Rohan | Computer Science | EECS |
| Rohan | Computer Science | IT |
+--------------+-------------------+------------------+
在前一种情况下,我可以从第一行本身获取有关student
的信息,但我无法知道获取主题行信息的边界是[0,1]; [1,2]和[2,4](除了可能是一些额外的SQL魔法)。
那么,您建议我遵循哪种方法?或者还有第三种更好的选择吗?
答案 0 :(得分:0)
我认为在单个查询中检索学生和主题是完全合适的。一些框架(ActiveRecord)确实可以很容易地像这样工作。用例通常是您从表和一堆“父”表中进行选择的地方,但是对于单个子关系来说,这样做没有任何问题。
它会变得棘手的是多个子关系,例如,如果您正在检索产品及其关联的子订单和库存水平,其中100个订单和10个库存水平等于1,000行且有大量冗余数据(所谓的一些圈子是“裂口陷阱”)。在这种情况下,您需要使用两个或三个查询来返回结果。